diff options
Diffstat (limited to 'lib/Sema')
42 files changed, 8257 insertions, 3722 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index ce01909f1858..2c70c0599ecf 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -159,6 +159,20 @@ public: S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_always) << DiagRange << isAlwaysTrue; } + + void compareBitwiseOr(const BinaryOperator *B) override { + if (HasMacroID(B)) + return; + + SourceRange DiagRange = B->getSourceRange(); + S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange; + } + + static bool hasActiveDiagnostics(DiagnosticsEngine &Diags, + SourceLocation Loc) { + return !Diags.isIgnored(diag::warn_tautological_overlap_comparison, Loc) || + !Diags.isIgnored(diag::warn_comparison_bitwise_or, Loc); + } }; } // anonymous namespace @@ -1215,7 +1229,7 @@ static StringRef getFallthroughAttrSpelling(Preprocessor &PP, tok::r_square, tok::r_square }; - bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17; + bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17 && !PP.getLangOpts().C2x; StringRef MacroName; if (PreferClangAttr) @@ -1224,24 +1238,19 @@ static StringRef getFallthroughAttrSpelling(Preprocessor &PP, MacroName = PP.getLastMacroWithSpelling(Loc, FallthroughTokens); if (MacroName.empty() && !PreferClangAttr) MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens); - if (MacroName.empty()) - MacroName = PreferClangAttr ? "[[clang::fallthrough]]" : "[[fallthrough]]"; + if (MacroName.empty()) { + if (!PreferClangAttr) + MacroName = "[[fallthrough]]"; + else if (PP.getLangOpts().CPlusPlus) + MacroName = "[[clang::fallthrough]]"; + else + MacroName = "__attribute__((fallthrough))"; + } return MacroName; } static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, bool PerFunction) { - // Only perform this analysis when using [[]] attributes. There is no good - // workflow for this warning when not using C++11. There is no good way to - // silence the warning (no attribute is available) unless we are using - // [[]] attributes. One could use pragmas to silence the warning, but as a - // general solution that is gross and not in the spirit of this warning. - // - // NOTE: This an intermediate solution. There are on-going discussions on - // how to properly support this warning outside of C++11 with an annotation. - if (!AC.getASTContext().getLangOpts().DoubleSquareBracketAttributes) - return; - FallthroughMapper FM(S); FM.TraverseStmt(AC.getBody()); @@ -1281,25 +1290,24 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, SourceLocation L = Label->getBeginLoc(); if (L.isMacroID()) continue; - if (S.getLangOpts().CPlusPlus11) { - const Stmt *Term = B->getTerminatorStmt(); - // Skip empty cases. - while (B->empty() && !Term && B->succ_size() == 1) { - B = *B->succ_begin(); - Term = B->getTerminatorStmt(); - } - if (!(B->empty() && Term && isa<BreakStmt>(Term))) { - Preprocessor &PP = S.getPreprocessor(); - StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L); - SmallString<64> TextToInsert(AnnotationSpelling); - TextToInsert += "; "; - S.Diag(L, diag::note_insert_fallthrough_fixit) << - AnnotationSpelling << - FixItHint::CreateInsertion(L, TextToInsert); - } + + const Stmt *Term = B->getTerminatorStmt(); + // Skip empty cases. + while (B->empty() && !Term && B->succ_size() == 1) { + B = *B->succ_begin(); + Term = B->getTerminatorStmt(); + } + if (!(B->empty() && Term && isa<BreakStmt>(Term))) { + Preprocessor &PP = S.getPreprocessor(); + StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L); + SmallString<64> TextToInsert(AnnotationSpelling); + TextToInsert += "; "; + S.Diag(L, diag::note_insert_fallthrough_fixit) + << AnnotationSpelling + << FixItHint::CreateInsertion(L, TextToInsert); } - S.Diag(L, diag::note_insert_break_fixit) << - FixItHint::CreateInsertion(L, "break; "); + S.Diag(L, diag::note_insert_break_fixit) + << FixItHint::CreateInsertion(L, "break; "); } } @@ -2076,10 +2084,9 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, .setAlwaysAdd(Stmt::AttributedStmtClass); } - // Install the logical handler for -Wtautological-overlap-compare + // Install the logical handler. llvm::Optional<LogicalErrorHandler> LEH; - if (!Diags.isIgnored(diag::warn_tautological_overlap_comparison, - D->getBeginLoc())) { + if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) { LEH.emplace(S); AC.getCFGBuildOptions().Observer = &*LEH; } @@ -2228,9 +2235,8 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, checkThrowInNonThrowingFunc(S, FD, AC); // If none of the previous checks caused a CFG build, trigger one here - // for -Wtautological-overlap-compare - if (!Diags.isIgnored(diag::warn_tautological_overlap_comparison, - D->getBeginLoc())) { + // for the logical error handler. + if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) { AC.getCFG(); } diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index 77e5eb095693..639231c87232 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -569,6 +569,7 @@ const char *DeclSpec::getSpecifierName(ConstexprSpecKind C) { case CSK_unspecified: return "unspecified"; case CSK_constexpr: return "constexpr"; case CSK_consteval: return "consteval"; + case CSK_constinit: return "constinit"; } llvm_unreachable("Unknown ConstexprSpecKind"); } @@ -1036,13 +1037,9 @@ bool DeclSpec::setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec, bool DeclSpec::SetConstexprSpec(ConstexprSpecKind ConstexprKind, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { - if (getConstexprSpecifier() != CSK_unspecified) { - if (getConstexprSpecifier() == CSK_consteval || ConstexprKind == CSK_consteval) - return BadSpecifier(ConstexprKind, getConstexprSpecifier(), PrevSpec, DiagID); - DiagID = diag::warn_duplicate_declspec; - PrevSpec = "constexpr"; - return true; - } + if (getConstexprSpecifier() != CSK_unspecified) + return BadSpecifier(ConstexprKind, getConstexprSpecifier(), PrevSpec, + DiagID); ConstexprSpecifier = ConstexprKind; ConstexprLoc = Loc; return false; @@ -1291,8 +1288,10 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { << (TypeSpecType == TST_char16 ? "char16_t" : "char32_t"); if (getConstexprSpecifier() == CSK_constexpr) S.Diag(ConstexprLoc, diag::warn_cxx98_compat_constexpr); - if (getConstexprSpecifier() == CSK_consteval) + else if (getConstexprSpecifier() == CSK_consteval) S.Diag(ConstexprLoc, diag::warn_cxx20_compat_consteval); + else if (getConstexprSpecifier() == CSK_constinit) + S.Diag(ConstexprLoc, diag::warn_cxx20_compat_constinit); // C++ [class.friend]p6: // No storage-class-specifier shall appear in the decl-specifier-seq // of a friend declaration. diff --git a/lib/Sema/OpenCLBuiltins.td b/lib/Sema/OpenCLBuiltins.td index 7e37e55dbafa..298614059467 100644 --- a/lib/Sema/OpenCLBuiltins.td +++ b/lib/Sema/OpenCLBuiltins.td @@ -20,75 +20,164 @@ //===----------------------------------------------------------------------===// // Versions of OpenCL class Version<int _Version> { - int Version = _Version; + int ID = _Version; } -def CL10: Version<100>; -def CL11: Version<110>; -def CL12: Version<120>; -def CL20: Version<200>; +def CLAll : Version< 0>; +def CL10 : Version<100>; +def CL11 : Version<110>; +def CL12 : Version<120>; +def CL20 : Version<200>; // Address spaces // Pointer types need to be assigned an address space. class AddressSpace<string _AS> { - string AddrSpace = _AS; + string Name = _AS; } -def default_as : AddressSpace<"clang::LangAS::Default">; -def private_as : AddressSpace<"clang::LangAS::opencl_private">; -def global_as : AddressSpace<"clang::LangAS::opencl_global">; -def constant_as : AddressSpace<"clang::LangAS::opencl_constant">; -def local_as : AddressSpace<"clang::LangAS::opencl_local">; -def generic_as : AddressSpace<"clang::LangAS::opencl_generic">; +def DefaultAS : AddressSpace<"clang::LangAS::Default">; +def PrivateAS : AddressSpace<"clang::LangAS::opencl_private">; +def GlobalAS : AddressSpace<"clang::LangAS::opencl_global">; +def ConstantAS : AddressSpace<"clang::LangAS::opencl_constant">; +def LocalAS : AddressSpace<"clang::LangAS::opencl_local">; +def GenericAS : AddressSpace<"clang::LangAS::opencl_generic">; -// Qualified Type. Allow to retrieve one ASTContext QualType. -class QualType<string _Name> { +// Qualified Type. These map to ASTContext::QualType. +class QualType<string _Name, bit _IsAbstract=0> { // Name of the field or function in a clang::ASTContext // E.g. Name="IntTy" for the int type, and "getIntPtrType()" for an intptr_t string Name = _Name; + // Some QualTypes in this file represent an abstract type for which there is + // no corresponding AST QualType, e.g. a GenType or an `image2d_t` type + // without access qualifiers. + bit IsAbstract = _IsAbstract; } -// Helper class to store type access qualifiers (volatile, const, ...). -class Qualifier<string _QualName> { - string QualName = _QualName; +// List of integers. +class IntList<string _Name, list<int> _List> { + string Name = _Name; + list<int> List = _List; } //===----------------------------------------------------------------------===// // OpenCL C classes for types //===----------------------------------------------------------------------===// -// OpenCL types (int, float, ...) +// OpenCL C basic data types (int, float, image2d_t, ...). +// Its child classes can represent concrete types (e.g. VectorType) or +// abstract types (e.g. GenType). class Type<string _Name, QualType _QTName> { - // Name of the Type + // Name of the Type. string Name = _Name; - // QualType associated with this type + // QualType associated with this type. QualType QTName = _QTName; - // Size of the vector (if applicable) - int VecWidth = 0; - // Is pointer + // Size of the vector (if applicable). + int VecWidth = 1; + // Is a pointer. bit IsPointer = 0; - // List of qualifiers associated with the type (volatile, ...) - list<Qualifier> QualList = []; - // Address space - string AddrSpace = "clang::LangAS::Default"; + // "const" qualifier. + bit IsConst = 0; + // "volatile" qualifier. + bit IsVolatile = 0; // Access qualifier. Must be one of ("RO", "WO", "RW"). string AccessQualifier = ""; + // Address space. + string AddrSpace = DefaultAS.Name; } -// OpenCL vector types (e.g. int2, int3, int16, float8, ...) +// OpenCL vector types (e.g. int2, int3, int16, float8, ...). class VectorType<Type _Ty, int _VecWidth> : Type<_Ty.Name, _Ty.QTName> { - int VecWidth = _VecWidth; + let VecWidth = _VecWidth; + let AccessQualifier = ""; + // Inherited fields + let IsPointer = _Ty.IsPointer; + let IsConst = _Ty.IsConst; + let IsVolatile = _Ty.IsVolatile; + let AddrSpace = _Ty.AddrSpace; } -// OpenCL pointer types (e.g. int*, float*, ...) -class PointerType<Type _Ty, AddressSpace _AS = global_as> : +// OpenCL pointer types (e.g. int*, float*, ...). +class PointerType<Type _Ty, AddressSpace _AS = DefaultAS> : Type<_Ty.Name, _Ty.QTName> { - bit IsPointer = 1; - string AddrSpace = _AS.AddrSpace; + let AddrSpace = _AS.Name; + // Inherited fields + let VecWidth = _Ty.VecWidth; + let IsPointer = 1; + let IsConst = _Ty.IsConst; + let IsVolatile = _Ty.IsVolatile; + let AccessQualifier = _Ty.AccessQualifier; +} + +// OpenCL const types (e.g. const int). +class ConstType<Type _Ty> : Type<_Ty.Name, _Ty.QTName> { + let IsConst = 1; + // Inherited fields + let VecWidth = _Ty.VecWidth; + let IsPointer = _Ty.IsPointer; + let IsVolatile = _Ty.IsVolatile; + let AccessQualifier = _Ty.AccessQualifier; + let AddrSpace = _Ty.AddrSpace; +} + +// OpenCL volatile types (e.g. volatile int). +class VolatileType<Type _Ty> : Type<_Ty.Name, _Ty.QTName> { + let IsVolatile = 1; + // Inherited fields + let VecWidth = _Ty.VecWidth; + let IsPointer = _Ty.IsPointer; + let IsConst = _Ty.IsConst; + let AccessQualifier = _Ty.AccessQualifier; + let AddrSpace = _Ty.AddrSpace; } -// OpenCL image types (e.g. image2d_t, ...) -class ImageType<Type _Ty, QualType _QTName, string _AccessQualifier> : - Type<_Ty.Name, _QTName> { +// OpenCL image types (e.g. image2d). +class ImageType<Type _Ty, string _AccessQualifier> : + Type<_Ty.Name, QualType<_Ty.QTName.Name#_AccessQualifier#"Ty", 0>> { + let VecWidth = 0; let AccessQualifier = _AccessQualifier; + // Inherited fields + let IsPointer = _Ty.IsPointer; + let IsConst = _Ty.IsConst; + let IsVolatile = _Ty.IsVolatile; + let AddrSpace = _Ty.AddrSpace; +} + +// List of Types. +class TypeList<string _Name, list<Type> _Type> { + string Name = _Name; + list<Type> List = _Type; +} + +// A GenericType is an abstract type that defines a set of types as a +// combination of Types and vector sizes. +// +// For example, if TypeList = <int, float> and VectorList = <1, 2, 4>, then it +// represents <int, int2, int4, float, float2, float4>. +// +// Some rules apply when using multiple GenericType arguments in a declaration: +// 1. The number of vector sizes must be equal or 1 for all gentypes in a +// declaration. +// 2. The number of Types must be equal or 1 for all gentypes in a +// declaration. +// 3. Generic types are combined by iterating over all generic types at once. +// For example, for the following GenericTypes +// GenT1 = GenericType<half, [1, 2]> and +// GenT2 = GenericType<float, int, [1, 2]> +// A declaration f(GenT1, GenT2) results in the combinations +// f(half, float), f(half2, float2), f(half, int), f(half2, int2) . +// 4. "sgentype" from the OpenCL specification is supported by specifying +// a single vector size. +// For example, for the following GenericTypes +// GenT = GenericType<half, int, [1, 2]> and +// SGenT = GenericType<half, int, [1]> +// A declaration f(GenT, SGenT) results in the combinations +// f(half, half), f(half2, half), f(int, int), f(int2, int) . +class GenericType<string _Ty, TypeList _TypeList, IntList _VectorList> : + Type<_Ty, QualType<"null", 1>> { + // Possible element types of the generic type. + TypeList TypeList = _TypeList; + // Possible vector sizes of the types in the TypeList. + IntList VectorList = _VectorList; + // The VecWidth field is ignored for GenericTypes. Use VectorList instead. + let VecWidth = 0; } //===----------------------------------------------------------------------===// @@ -103,141 +192,124 @@ class Builtin<string _Name, list<Type> _Signature> { list<Type> Signature = _Signature; // OpenCL Extension to which the function belongs (cl_khr_subgroups, ...) string Extension = ""; - // OpenCL Version to which the function belongs (CL10, ...) - Version Version = CL10; + // Version of OpenCL from which the function is available (e.g.: CL10). + // MinVersion is inclusive. + Version MinVersion = CL10; + // Version of OpenCL from which the function is not supported anymore. + // MaxVersion is exclusive. + // CLAll makes the function available for all versions. + Version MaxVersion = CLAll; } //===----------------------------------------------------------------------===// -// Multiclass definitions +// Definitions of OpenCL C types //===----------------------------------------------------------------------===// -// multiclass BifN: Creates Builtin class instances for OpenCL builtin -// functions with N arguments. -// _Name : Name of the function -// _Signature : Signature of the function (list of the Type used by the -// function, the first one being the return type). -// _IsVector : List of bit indicating if the type in the _Signature at the -// same index is to be a vector in the multiple overloads. The -// list must have at least one non-zero value. -multiclass Bif0<string _Name, list<Type> _Signature, list<bit> _IsVector> { - def : Builtin<_Name, _Signature>; - foreach v = [2, 3, 4, 8, 16] in { - def : Builtin<_Name, - [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0])]>; - } -} -multiclass Bif1<string _Name, list<Type> _Signature, list<bit> _IsVector> { - def : Builtin<_Name, _Signature>; - foreach v = [2, 3, 4, 8, 16] in { - def : Builtin<_Name, - [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0]), - !if(_IsVector[1], VectorType<_Signature[1], v>, _Signature[1])]>; - } -} -multiclass Bif2<string _Name, list<Type> _Signature, list<bit> _IsVector> { - def : Builtin<_Name, _Signature>; - foreach v = [2, 3, 4, 8, 16] in { - def : Builtin<_Name, - [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0]), - !if(_IsVector[1], VectorType<_Signature[1], v>, _Signature[1]), - !if(_IsVector[2], VectorType<_Signature[2], v>, _Signature[2])]>; - } -} -multiclass Bif3<string _Name, list<Type> _Signature, list<bit> _IsVector> { - def : Builtin<_Name, _Signature>; - foreach v = [2, 3, 4, 8, 16] in { - def : Builtin<_Name, - [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0]), - !if(_IsVector[1], VectorType<_Signature[1], v>, _Signature[1]), - !if(_IsVector[2], VectorType<_Signature[2], v>, _Signature[2]), - !if(_IsVector[3], VectorType<_Signature[3], v>, _Signature[3])]>; - } -} + +// OpenCL v1.0/1.2/2.0 s6.1.1: Built-in Scalar Data Types. +def Bool : Type<"bool", QualType<"BoolTy">>; +def Char : Type<"char", QualType<"CharTy">>; +def UChar : Type<"uchar", QualType<"UnsignedCharTy">>; +def Short : Type<"short", QualType<"ShortTy">>; +def UShort : Type<"ushort", QualType<"UnsignedShortTy">>; +def Int : Type<"int", QualType<"IntTy">>; +def UInt : Type<"uint", QualType<"UnsignedIntTy">>; +def Long : Type<"long", QualType<"LongTy">>; +def ULong : Type<"ulong", QualType<"UnsignedLongTy">>; +def Float : Type<"float", QualType<"FloatTy">>; +def Double : Type<"double", QualType<"DoubleTy">>; +def Half : Type<"half", QualType<"HalfTy">>; +def Size : Type<"size_t", QualType<"getSizeType()">>; +def PtrDiff : Type<"ptrdiff_t", QualType<"getPointerDiffType()">>; +def IntPtr : Type<"intptr_t", QualType<"getIntPtrType()">>; +def UIntPtr : Type<"uintPtr_t", QualType<"getUIntPtrType()">>; +def Void : Type<"void_t", QualType<"VoidTy">>; + +// OpenCL v1.0/1.2/2.0 s6.1.2: Built-in Vector Data Types. +// Built-in vector data types are created by TableGen's OpenCLBuiltinEmitter. + +// OpenCL v1.0/1.2/2.0 s6.1.3: Other Built-in Data Types. +// The image definitions are "abstract". They should not be used without +// specifying an access qualifier (RO/WO/RW). +def Image1d : Type<"Image1d", QualType<"OCLImage1d", 1>>; +def Image2d : Type<"Image2d", QualType<"OCLImage2d", 1>>; +def Image3d : Type<"Image3d", QualType<"OCLImage3d", 1>>; +def Image1dArray : Type<"Image1dArray", QualType<"OCLImage1dArray", 1>>; +def Image1dBuffer : Type<"Image1dBuffer", QualType<"OCLImage1dBuffer", 1>>; +def Image2dArray : Type<"Image2dArray", QualType<"OCLImage2dArray", 1>>; +def Image2dDepth : Type<"Image2dDepth", QualType<"OCLImage2dDepth", 1>>; +def Image2dArrayDepth : Type<"Image2dArrayDepth", QualType<"OCLImage2dArrayDepth", 1>>; +def Image2dMsaa : Type<"Image2dMsaa", QualType<"OCLImage2dMSAA", 1>>; +def Image2dArrayMsaa : Type<"Image2dArrayMsaa", QualType<"OCLImage2dArrayMSAA", 1>>; +def Image2dMsaaDepth : Type<"Image2dMsaaDepth", QualType<"OCLImage2dMSAADepth", 1>>; +def Image2dArrayMsaaDepth : Type<"Image2dArrayMsaaDepth", QualType<"OCLImage2dArrayMSAADepth", 1>>; + +def Sampler : Type<"Sampler", QualType<"OCLSamplerTy">>; +def Event : Type<"Event", QualType<"OCLEventTy">>; + //===----------------------------------------------------------------------===// -// Definitions of OpenCL C types +// Definitions of OpenCL gentype variants //===----------------------------------------------------------------------===// -// OpenCL v1.2 s6.1.1: Built-in Scalar Data Types -def bool_t : Type<"bool", QualType<"BoolTy">>; -def char_t : Type<"char", QualType<"CharTy">>; -def uchar_t : Type<"uchar", QualType<"UnsignedCharTy">>; -def short_t : Type<"short", QualType<"ShortTy">>; -def ushort_t : Type<"ushort", QualType<"UnsignedShortTy">>; -def int_t : Type<"int", QualType<"IntTy">>; -def uint_t : Type<"uint", QualType<"UnsignedIntTy">>; -def long_t : Type<"long", QualType<"LongTy">>; -def ulong_t : Type<"ulong", QualType<"UnsignedLongTy">>; -def float_t : Type<"float", QualType<"FloatTy">>; -def double_t : Type<"double", QualType<"DoubleTy">>; -def half_t : Type<"half", QualType<"HalfTy">>; -def size_t : Type<"size_t", QualType<"getSizeType()">>; -def ptrdiff_t : Type<"ptrdiff_t", QualType<"getPointerDiffType()">>; -def intptr_t : Type<"intptr_t", QualType<"getIntPtrType()">>; -def uintptr_t : Type<"uintptr_t", QualType<"getUIntPtrType()">>; -def void_t : Type<"void", QualType<"VoidTy">>; - -// OpenCL v1.2 s6.1.2: Built-in Vector Data Types -foreach v = [2, 3, 4, 8, 16] in { - def char#v#_t : VectorType<char_t, v>; - def uchar#v#_t : VectorType<uchar_t, v>; - def short#v#_t : VectorType<short_t, v>; - def ushort#v#_t : VectorType<ushort_t, v>; - def "int"#v#_t : VectorType<int_t, v>; - def uint#v#_t : VectorType<uint_t, v>; - def long#v#_t : VectorType<long_t, v>; - def ulong#v#_t : VectorType<ulong_t, v>; - def float#v#_t : VectorType<float_t, v>; - def double#v#_t : VectorType<double_t, v>; - def half#v#_t : VectorType<half_t, v>; -} - -// OpenCL v1.2 s6.1.3: Other Built-in Data Types -// These definitions with a "null" name are "abstract". They should not -// be used in definitions of Builtin functions. -def image2d_t : Type<"image2d_t", QualType<"null">>; -def image3d_t : Type<"image3d_t", QualType<"null">>; -def image2d_array_t : Type<"image2d_array_t", QualType<"null">>; -def image1d_t : Type<"image1d_t", QualType<"null">>; -def image1d_buffer_t : Type<"image1d_buffer_t", QualType<"null">>; -def image1d_array_t : Type<"image1d_array_t", QualType<"null">>; -// Unlike the few functions above, the following definitions can be used -// in definitions of Builtin functions (they have a QualType with a name). -foreach v = ["RO", "WO", "RW"] in { - def image2d_#v#_t : ImageType<image2d_t, - QualType<"OCLImage2d"#v#"Ty">, - v>; - def image3d_#v#_t : ImageType<image3d_t, - QualType<"OCLImage3d"#v#"Ty">, - v>; - def image2d_array#v#_t : ImageType<image2d_array_t, - QualType<"OCLImage2dArray"#v#"Ty">, - v>; - def image1d_#v#_t : ImageType<image1d_t, - QualType<"OCLImage1d"#v#"Ty">, - v>; - def image1d_buffer#v#_t : ImageType<image1d_buffer_t, - QualType<"OCLImage1dBuffer"#v#"Ty">, - v>; - def image1d_array#v#_t : ImageType<image1d_array_t, - QualType<"OCLImage1dArray"#v#"Ty">, - v>; -} - -def sampler_t : Type<"sampler_t", QualType<"OCLSamplerTy">>; -def event_t : Type<"event_t", QualType<"OCLEventTy">>; +// The OpenCL specification often uses "gentype" in builtin function +// declarations to indicate that a builtin function is available with various +// argument and return types. The types represented by "gentype" vary between +// different parts of the specification. The following definitions capture +// the different type lists for gentypes in different parts of the +// specification. + +// Vector width lists. +def VecAndScalar: IntList<"VecAndScalar", [1, 2, 3, 4, 8, 16]>; +def VecNoScalar : IntList<"VecNoScalar", [2, 3, 4, 8, 16]>; +def Vec1 : IntList<"Vec1", [1]>; + +// Type lists. +def TLAll : TypeList<"TLAll", [Char, UChar, Short, UShort, Int, UInt, Long, ULong, Float, Double, Half]>; +def TLFloat : TypeList<"TLFloat", [Float, Double, Half]>; + +def TLAllInts : TypeList<"TLAllInts", [Char, UChar, Short, UShort, Int, UInt, Long, ULong]>; + +// GenType definitions for multiple base types (e.g. all floating point types, +// or all integer types). +// All types +def AGenTypeN : GenericType<"AGenTypeN", TLAll, VecAndScalar>; +def AGenTypeNNoScalar : GenericType<"AGenTypeNNoScalar", TLAll, VecNoScalar>; +// All integer +def AIGenType1 : GenericType<"AIGenType1", TLAllInts, Vec1>; +def AIGenTypeN : GenericType<"AIGenTypeN", TLAllInts, VecAndScalar>; +def AIGenTypeNNoScalar : GenericType<"AIGenTypeNNoScalar", TLAllInts, VecNoScalar>; +// Float +def FGenTypeN : GenericType<"FGenTypeN", TLFloat, VecAndScalar>; + +// GenType definitions for every single base type (e.g. fp32 only). +// Names are like: GenTypeFloatVecAndScalar. +foreach Type = [Char, UChar, Short, UShort, + Int, UInt, Long, ULong, + Float, Double, Half] in { + foreach VecSizes = [VecAndScalar, VecNoScalar] in { + def "GenType" # Type # VecSizes : + GenericType<"GenType" # Type # VecSizes, + TypeList<"GL" # Type.Name, [Type]>, + VecSizes>; + } +} + //===----------------------------------------------------------------------===// // Definitions of OpenCL builtin functions //===----------------------------------------------------------------------===// -// OpenCL v1.2 s6.2.3: Explicit Conversions -// Generate the convert_ builtins. -foreach RType = [float_t, double_t, char_t, uchar_t, short_t, ushort_t, - int_t, uint_t, long_t, ulong_t] in { - foreach IType = [float_t, double_t, char_t, uchar_t, short_t, ushort_t, - int_t, uint_t, long_t, ulong_t] in { +//-------------------------------------------------------------------- +// OpenCL v1.1/1.2/2.0 s6.2.3 - Explicit conversions. +// OpenCL v2.0 Extensions s5.1.1 and s6.1.1 - Conversions. + +// Generate the convert_* builtins functions. +foreach RType = [Float, Double, Half, Char, UChar, Short, + UShort, Int, UInt, Long, ULong] in { + foreach IType = [Float, Double, Half, Char, UChar, Short, + UShort, Int, UInt, Long, ULong] in { foreach sat = ["", "_sat"] in { - foreach rte = ["", "_rte", "_rtz", "_rtp", "_rtn"] in { - def : Builtin<"convert_" # RType.Name # sat # rte, [RType, IType]>; + foreach rnd = ["", "_rte", "_rtn", "_rtp", "_rtz"] in { + def : Builtin<"convert_" # RType.Name # sat # rnd, [RType, IType]>; foreach v = [2, 3, 4, 8, 16] in { - def : Builtin<"convert_" # RType.Name # v # sat # rte, + def : Builtin<"convert_" # RType.Name # v # sat # rnd, [VectorType<RType, v>, VectorType<IType, v>]>; } @@ -246,51 +318,357 @@ foreach RType = [float_t, double_t, char_t, uchar_t, short_t, ushort_t, } } -// OpenCL v1.2 s6.12.1: Work-Item Functions -def get_work_dim : Builtin<"get_work_dim", [uint_t]>; +//-------------------------------------------------------------------- +// 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]>; 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_t, uint_t]>; + def : Builtin<name, [Size, UInt]>; +} + +let MinVersion = CL20 in { + def : Builtin<"get_enqueued_local_size", [Size, UInt]>; + foreach name = ["get_global_linear_id", "get_local_linear_id"] in { + def : Builtin<name, [Size]>; + } +} + +//-------------------------------------------------------------------- +// 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 +// --- Table 15 --- +// Variants for OpenCL versions below 2.0, using pointers to the global, local +// and private address spaces. +let MaxVersion = CL20 in { + foreach AS = [GlobalAS, LocalAS, PrivateAS] in { + foreach VSize = [2, 3, 4, 8, 16] in { + foreach name = ["vload" # VSize] in { + def : Builtin<name, [VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, AS>]>; + def : Builtin<name, [VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, AS>]>; + def : Builtin<name, [VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, AS>]>; + def : Builtin<name, [VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, AS>]>; + def : Builtin<name, [VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, AS>]>; + def : Builtin<name, [VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, AS>]>; + def : Builtin<name, [VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, AS>]>; + def : Builtin<name, [VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, AS>]>; + def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, AS>]>; + def : Builtin<name, [VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, AS>]>; + def : Builtin<name, [VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, AS>]>; + } + foreach name = ["vstore" # VSize] in { + def : Builtin<name, [Void, VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, AS>]>; + def : Builtin<name, [Void, VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, AS>]>; + def : Builtin<name, [Void, VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, AS>]>; + def : Builtin<name, [Void, VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, AS>]>; + def : Builtin<name, [Void, VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, AS>]>; + def : Builtin<name, [Void, VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, AS>]>; + def : Builtin<name, [Void, VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, AS>]>; + def : Builtin<name, [Void, VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, AS>]>; + def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, AS>]>; + def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, AS>]>; + def : Builtin<name, [Void, VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, AS>]>; + } + foreach name = ["vloada_half" # VSize] in { + def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>; + } + foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in { + foreach name = ["vstorea_half" # VSize # rnd] in { + def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, AS>]>; + def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Half, AS>]>; + } + } + } + } +} +// Variants for OpenCL versions above 2.0, using pointers to the generic +// address space. +let MinVersion = CL20 in { + foreach VSize = [2, 3, 4, 8, 16] in { + foreach name = ["vload" # VSize] in { + def : Builtin<name, [VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, GenericAS>]>; + def : Builtin<name, [VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, GenericAS>]>; + def : Builtin<name, [VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, GenericAS>]>; + def : Builtin<name, [VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, GenericAS>]>; + def : Builtin<name, [VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, GenericAS>]>; + def : Builtin<name, [VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, GenericAS>]>; + def : Builtin<name, [VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, GenericAS>]>; + def : Builtin<name, [VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, GenericAS>]>; + def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, GenericAS>]>; + def : Builtin<name, [VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, GenericAS>]>; + def : Builtin<name, [VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, GenericAS>]>; + } + foreach name = ["vstore" # VSize] in { + def : Builtin<name, [Void, VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, GenericAS>]>; + def : Builtin<name, [Void, VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, GenericAS>]>; + def : Builtin<name, [Void, VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, GenericAS>]>; + def : Builtin<name, [Void, VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, GenericAS>]>; + def : Builtin<name, [Void, VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, GenericAS>]>; + def : Builtin<name, [Void, VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, GenericAS>]>; + def : Builtin<name, [Void, VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, GenericAS>]>; + def : Builtin<name, [Void, VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, GenericAS>]>; + def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, GenericAS>]>; + def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, GenericAS>]>; + def : Builtin<name, [Void, VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, GenericAS>]>; + } + foreach name = ["vloada_half" # VSize] in { + def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, GenericAS>]>; + } + foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in { + foreach name = ["vstorea_half" # VSize # rnd] in { + def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, GenericAS>]>; + def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Half, GenericAS>]>; + } + } + } +} +// Variants using pointers to the constant address space. +foreach VSize = [2, 3, 4, 8, 16] in { + foreach name = ["vload" # VSize] in { + def : Builtin<name, [VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, ConstantAS>]>; + def : Builtin<name, [VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, ConstantAS>]>; + def : Builtin<name, [VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, ConstantAS>]>; + def : Builtin<name, [VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, ConstantAS>]>; + def : Builtin<name, [VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, ConstantAS>]>; + def : Builtin<name, [VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, ConstantAS>]>; + def : Builtin<name, [VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, ConstantAS>]>; + def : Builtin<name, [VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, ConstantAS>]>; + def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, ConstantAS>]>; + def : Builtin<name, [VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, ConstantAS>]>; + def : Builtin<name, [VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, ConstantAS>]>; + } + foreach name = ["vloada_half" # VSize] in { + def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, ConstantAS>]>; + } + foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in { + foreach name = ["vstorea_half" # VSize # rnd] in { + def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, ConstantAS>]>; + def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Half, ConstantAS>]>; + } + } +} + +//-------------------------------------------------------------------- +// 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 +// OpenCL Extension v2.0 s5.1.7 and s6.1.7: Async Copies from Global to Local Memory, Local to Global Memory, and Prefetch +// --- Table 18 --- +foreach name = ["async_work_group_copy"] in { + def : Builtin<name, [Event, PointerType<AGenTypeN, LocalAS>, PointerType<ConstType<AGenTypeN>, GlobalAS>, Size, Event]>; + def : Builtin<name, [Event, PointerType<AGenTypeN, GlobalAS>, PointerType<ConstType<AGenTypeN>, LocalAS>, Size, Event]>; +} +foreach name = ["async_work_group_strided_copy"] in { + def : Builtin<name, [Event, PointerType<AGenTypeN, LocalAS>, PointerType<ConstType<AGenTypeN>, GlobalAS>, Size, Size, Event]>; + def : Builtin<name, [Event, PointerType<AGenTypeN, GlobalAS>, PointerType<ConstType<AGenTypeN>, LocalAS>, Size, Size, Event]>; +} +foreach name = ["wait_group_events"] in { + def : Builtin<name, [Void, Int, PointerType<Event, GenericAS>]>; +} +foreach name = ["prefetch"] in { + def : Builtin<name, [Void, PointerType<ConstType<AGenTypeN>, GlobalAS>, Size]>; +} + +//-------------------------------------------------------------------- +// OpenCL v2.0 s6.13.11 - Atomics Functions. +// 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. +// --- 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]>; + } + 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]>; + } } // OpenCL v1.2 s6.12.2: Math Functions foreach name = ["acos", "acosh", "acospi", "asin", "asinh", "asinpi", "atan", "atanh", "atanpi"] in { - foreach type = [float_t, double_t, half_t] in { - defm : Bif1<name, [type, type], [1, 1]>; - } + def : Builtin<name, [FGenTypeN, FGenTypeN]>; } foreach name = ["atan2", "atan2pi"] in { - foreach type = [float_t, double_t, half_t] in { - defm : Bif2<name, [type, type, type], [1, 1, 1]>; - } + def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN]>; } foreach name = ["fmax", "fmin"] in { - foreach type = [float_t, double_t, half_t] in { - defm : Bif2<name, [type, type, type], [1, 1, 1]>; - defm : Bif2<name, [type, type, type], [1, 1, 0]>; + 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.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]>; +} + +//-------------------------------------------------------------------- +// OpenCL v1.1 s6.11.3, v1.2 s6.12.14, v2.0 s6.13.14: Image Read and Write Functions +// OpenCL Extension v2.0 s5.1.8 and s6.1.8: Image Read and Write Functions +// --- 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]>; + } +} +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>]>; } } +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>]>; + } +} +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>]>; +} -// OpenCL v1.2 s6.12.14: Built-in Image Read Functions -def read_imagef : Builtin<"read_imagef", - [float4_t, image2d_RO_t, VectorType<int_t, 2>]>; -def write_imagef : Builtin<"write_imagef", - [void_t, - image2d_WO_t, - VectorType<int_t, 2>, - VectorType<float_t, 4>]>; +// --- 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>]>; + } + 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>]>; + } + 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", [Float, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>]>; + def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>]>; +} + +// --- Table 24: Image Write Functions --- +foreach aQual = ["WO", "RW"] in { + foreach imgTy = [Image2d] in { + def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Float, 4>]>; + def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Int, 4>]>; + def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<UInt, 4>]>; + } + foreach imgTy = [Image2dArray] in { + def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<Float, 4>]>; + def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<Int, 4>]>; + def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<UInt, 4>]>; + } + foreach imgTy = [Image1d, Image1dBuffer] in { + def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, Int, VectorType<Float, 4>]>; + def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, Int, VectorType<Int, 4>]>; + def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, Int, VectorType<UInt, 4>]>; + } + foreach imgTy = [Image1dArray] in { + def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Float, 4>]>; + def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Int, 4>]>; + def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<UInt, 4>]>; + } + foreach imgTy = [Image3d] in { + def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<Float, 4>]>; + def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<Int, 4>]>; + def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<UInt, 4>]>; + } + def : Builtin<"write_imagef", [Void, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>, Float]>; + def : Builtin<"write_imagef", [Void, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>, Float]>; +} + +// --- Table 25: Image Query Functions --- +foreach aQual = ["RO", "WO", "RW"] in { + foreach imgTy = [Image1d, Image1dBuffer, Image2d, Image3d, + Image1dArray, Image2dArray, Image2dDepth, + Image2dArrayDepth] in { + foreach name = ["get_image_width", "get_image_channel_data_type", + "get_image_channel_order"] in { + def : Builtin<name, [Int, ImageType<imgTy, aQual>]>; + } + } + foreach imgTy = [Image2d, Image3d, Image2dArray, Image2dDepth, + Image2dArrayDepth] in { + def : Builtin<"get_image_height", [Int, ImageType<imgTy, aQual>]>; + } + def : Builtin<"get_image_depth", [Int, ImageType<Image3d, aQual>]>; + foreach imgTy = [Image2d, Image2dArray, Image2dDepth, + Image2dArrayDepth] in { + def : Builtin<"get_image_dim", [VectorType<Int, 2>, ImageType<imgTy, aQual>]>; + } + def : Builtin<"get_image_dim", [VectorType<Int, 4>, ImageType<Image3d, aQual>]>; + foreach imgTy = [Image1dArray, Image2dArray, Image2dArrayDepth] in { + def : Builtin<"get_image_array_size", [Size, ImageType<imgTy, aQual>]>; + } +} + +// OpenCL extension v2.0 s5.1.9: Built-in Image Read Functions +// --- Table 8 --- +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>]>; + } + foreach imgTy = [Image3d, Image2dArray] in { + def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 4>]>; + } + foreach imgTy = [Image1d] in { + def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, coordTy]>; + } + } + } +} +// OpenCL extension v2.0 s5.1.10: Built-in Image Sampler-less Read Functions +// --- Table 9 --- +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>]>; + } + foreach imgTy = [Image3d, Image2dArray] in { + def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>; + } + foreach imgTy = [Image1d, Image1dBuffer] in { + def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Int]>; + } + } +} +// OpenCL extension v2.0 s5.1.11: Built-in Image Write Functions +// --- Table 10 --- +foreach aQual = ["WO", "RW"] in { + foreach name = ["write_imageh"] in { + def : Builtin<name, [Void, ImageType<Image2d, aQual>, VectorType<Int, 2>, VectorType<Half, 4>]>; + def : Builtin<name, [Void, ImageType<Image2dArray, aQual>, VectorType<Int, 4>, VectorType<Half, 4>]>; + def : Builtin<name, [Void, ImageType<Image1d, aQual>, Int, VectorType<Half, 4>]>; + def : Builtin<name, [Void, ImageType<Image1dBuffer, aQual>, Int, VectorType<Half, 4>]>; + def : Builtin<name, [Void, ImageType<Image1dArray, aQual>, VectorType<Int, 2>, VectorType<Half, 4>]>; + def : Builtin<name, [Void, ImageType<Image3d, aQual>, VectorType<Int, 4>, VectorType<Half, 4>]>; + } +} // OpenCL v2.0 s9.17.3: Additions to section 6.13.1: Work-Item Functions -let Version = CL20 in { +let MinVersion = CL20 in { let Extension = "cl_khr_subgroups" in { - def get_sub_group_size : Builtin<"get_sub_group_size", [uint_t]>; - def get_max_sub_group_size : Builtin<"get_max_sub_group_size", [uint_t]>; - def get_num_sub_groups : Builtin<"get_num_sub_groups", [uint_t]>; + 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]>; } } diff --git a/lib/Sema/ParsedAttr.cpp b/lib/Sema/ParsedAttr.cpp index 5c04443460bc..5d0a734f237a 100644 --- a/lib/Sema/ParsedAttr.cpp +++ b/lib/Sema/ParsedAttr.cpp @@ -100,71 +100,6 @@ void AttributePool::takePool(AttributePool &pool) { pool.Attrs.clear(); } -#include "clang/Sema/AttrParsedAttrKinds.inc" - -static StringRef normalizeAttrScopeName(StringRef ScopeName, - ParsedAttr::Syntax SyntaxUsed) { - // Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name - // to be "clang". - if (SyntaxUsed == ParsedAttr::AS_CXX11 || - SyntaxUsed == ParsedAttr::AS_C2x) { - if (ScopeName == "__gnu__") - ScopeName = "gnu"; - else if (ScopeName == "_Clang") - ScopeName = "clang"; - } - return ScopeName; -} - -static StringRef normalizeAttrName(StringRef AttrName, - StringRef NormalizedScopeName, - ParsedAttr::Syntax SyntaxUsed) { - // Normalize the attribute name, __foo__ becomes foo. This is only allowable - // for GNU attributes, and attributes using the double square bracket syntax. - bool ShouldNormalize = - SyntaxUsed == ParsedAttr::AS_GNU || - ((SyntaxUsed == ParsedAttr::AS_CXX11 || - SyntaxUsed == ParsedAttr::AS_C2x) && - (NormalizedScopeName == "gnu" || NormalizedScopeName == "clang")); - if (ShouldNormalize && AttrName.size() >= 4 && AttrName.startswith("__") && - AttrName.endswith("__")) - AttrName = AttrName.slice(2, AttrName.size() - 2); - - return AttrName; -} - -ParsedAttr::Kind ParsedAttr::getKind(const IdentifierInfo *Name, - const IdentifierInfo *ScopeName, - Syntax SyntaxUsed) { - StringRef AttrName = Name->getName(); - - SmallString<64> FullName; - if (ScopeName) - FullName += normalizeAttrScopeName(ScopeName->getName(), SyntaxUsed); - - AttrName = normalizeAttrName(AttrName, FullName, SyntaxUsed); - - // Ensure that in the case of C++11 attributes, we look for '::foo' if it is - // unscoped. - if (ScopeName || SyntaxUsed == AS_CXX11 || SyntaxUsed == AS_C2x) - FullName += "::"; - FullName += AttrName; - - return ::getAttrKind(FullName, SyntaxUsed); -} - -unsigned ParsedAttr::getAttributeSpellingListIndex() const { - // Both variables will be used in tablegen generated - // attribute spell list index matching code. - auto Syntax = static_cast<ParsedAttr::Syntax>(SyntaxUsed); - StringRef Scope = - ScopeName ? normalizeAttrScopeName(ScopeName->getName(), Syntax) : ""; - StringRef Name = normalizeAttrName(AttrName->getName(), Scope, Syntax); - -#include "clang/Sema/AttrSpellingListIndex.inc" - -} - struct ParsedAttrInfo { unsigned NumArgs : 4; unsigned OptArgs : 4; diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 11fed28b52db..bedea2167950 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -22,6 +22,7 @@ #include "clang/AST/StmtCXX.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/Stack.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" @@ -37,6 +38,7 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TemplateInstCallback.h" +#include "clang/Sema/TypoCorrection.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallSet.h" #include "llvm/Support/TimeProfiler.h" @@ -181,7 +183,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, InitDataSharingAttributesStack(); std::unique_ptr<sema::SemaPPCallbacks> Callbacks = - llvm::make_unique<sema::SemaPPCallbacks>(); + std::make_unique<sema::SemaPPCallbacks>(); SemaPPCallbackHandler = Callbacks.get(); PP.addPPCallbacks(std::move(Callbacks)); SemaPPCallbackHandler->set(*this); @@ -335,7 +337,13 @@ void Sema::Initialize() { addImplicitTypedef(#ExtType, Context.Id##Ty); \ setOpenCLExtensionForType(Context.Id##Ty, #Ext); #include "clang/Basic/OpenCLExtensionTypes.def" - }; + } + + if (Context.getTargetInfo().hasAArch64SVETypes()) { +#define SVE_TYPE(Name, Id, SingletonId) \ + addImplicitTypedef(Name, Context.SingletonId); +#include "clang/Basic/AArch64SVEACLETypes.def" + } if (Context.getTargetInfo().hasBuiltinMSVaList()) { DeclarationName MSVaList = &Context.Idents.get("__builtin_ms_va_list"); @@ -376,8 +384,19 @@ Sema::~Sema() { // Detach from the PP callback handler which outlives Sema since it's owned // by the preprocessor. SemaPPCallbackHandler->reset(); +} + +void Sema::warnStackExhausted(SourceLocation Loc) { + // Only warn about this once. + if (!WarnedStackExhausted) { + Diag(Loc, diag::warn_stack_exhausted); + WarnedStackExhausted = true; + } +} - assert(DelayedTypos.empty() && "Uncorrected typos!"); +void Sema::runWithSufficientStackSpace(SourceLocation Loc, + llvm::function_ref<void()> Fn) { + clang::runWithSufficientStackSpace([&] { warnStackExhausted(Loc); }, Fn); } /// makeUnavailableInSystemHeader - There is an error in the current @@ -907,9 +926,22 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) { PerformPendingInstantiations(); } + // Finalize analysis of OpenMP-specific constructs. + if (LangOpts.OpenMP) + finalizeOpenMPDelayedAnalysis(); + assert(LateParsedInstantiations.empty() && "end of TU template instantiation should not create more " "late-parsed templates"); + + // Report diagnostics for uncorrected delayed typos. Ideally all of them + // should have been corrected by that time, but it is very hard to cover all + // cases in practice. + for (const auto &Typo : DelayedTypos) { + // We pass an empty TypoCorrection to indicate no correction was performed. + Typo.second.DiagHandler(TypoCorrection()); + } + DelayedTypos.clear(); } /// ActOnEndOfTranslationUnit - This is called at the very end of the @@ -961,6 +993,7 @@ void Sema::ActOnEndOfTranslationUnit() { // All dllexport classes should have been processed already. assert(DelayedDllExportClasses.empty()); + assert(DelayedDllExportMemberFunctions.empty()); // Remove file scoped decls that turned out to be used. UnusedFileScopedDecls.erase( @@ -1086,8 +1119,8 @@ void Sema::ActOnEndOfTranslationUnit() { // Set the length of the array to 1 (C99 6.9.2p5). Diag(VD->getLocation(), diag::warn_tentative_incomplete_array); llvm::APInt One(Context.getTypeSize(Context.getSizeType()), true); - QualType T = Context.getConstantArrayType(ArrayT->getElementType(), - One, ArrayType::Normal, 0); + QualType T = Context.getConstantArrayType(ArrayT->getElementType(), One, + nullptr, ArrayType::Normal, 0); VD->setType(T); } else if (RequireCompleteType(VD->getLocation(), VD->getType(), diag::err_tentative_def_incomplete_type)) @@ -1282,7 +1315,7 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) { PartialDiagnostic(DiagInfo, Context.getDiagAllocator())); } - Diags.setLastDiagnosticIgnored(); + Diags.setLastDiagnosticIgnored(true); Diags.Clear(); return; @@ -1307,7 +1340,7 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) { PartialDiagnostic(DiagInfo, Context.getDiagAllocator())); } - Diags.setLastDiagnosticIgnored(); + Diags.setLastDiagnosticIgnored(true); Diags.Clear(); // Now the diagnostic state is clear, produce a C++98 compatibility @@ -1316,7 +1349,7 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) { // The last diagnostic which Sema produced was ignored. Suppress any // notes attached to it. - Diags.setLastDiagnosticIgnored(); + Diags.setLastDiagnosticIgnored(true); return; } @@ -1330,7 +1363,7 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) { } // Suppress this diagnostic. - Diags.setLastDiagnosticIgnored(); + Diags.setLastDiagnosticIgnored(true); Diags.Clear(); return; } @@ -1376,7 +1409,7 @@ static void emitCallStackNotes(Sema &S, FunctionDecl *FD) { // Emit any deferred diagnostics for FD and erase them from the map in which // they're stored. -static void emitDeferredDiags(Sema &S, FunctionDecl *FD) { +static void emitDeferredDiags(Sema &S, FunctionDecl *FD, bool ShowCallStack) { auto It = S.DeviceDeferredDiags.find(FD); if (It == S.DeviceDeferredDiags.end()) return; @@ -1395,7 +1428,7 @@ static void emitDeferredDiags(Sema &S, FunctionDecl *FD) { // FIXME: Should this be called after every warning/error emitted in the loop // above, instead of just once per function? That would be consistent with // how we handle immediate errors, but it also seems like a bit much. - if (HasWarningOrError) + if (HasWarningOrError && ShowCallStack) emitCallStackNotes(S, FD); } @@ -1498,7 +1531,7 @@ void Sema::markKnownEmitted( assert(!IsKnownEmitted(S, C.Callee) && "Worklist should not contain known-emitted functions."); S.DeviceKnownEmittedFns[C.Callee] = {C.Caller, C.Loc}; - emitDeferredDiags(S, C.Callee); + emitDeferredDiags(S, C.Callee, C.Caller); // If this is a template instantiation, explore its callgraph as well: // Non-dependent calls are part of the template's callgraph, while dependent @@ -1535,8 +1568,9 @@ void Sema::markKnownEmitted( } Sema::DeviceDiagBuilder Sema::targetDiag(SourceLocation Loc, unsigned DiagID) { - if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice) - return diagIfOpenMPDeviceCode(Loc, DiagID); + if (LangOpts.OpenMP) + return LangOpts.OpenMPIsDevice ? diagIfOpenMPDeviceCode(Loc, DiagID) + : diagIfOpenMPHostCode(Loc, DiagID); if (getLangOpts().CUDA) return getLangOpts().CUDAIsDevice ? CUDADiagIfDeviceCode(Loc, DiagID) : CUDADiagIfHostCode(Loc, DiagID); @@ -1790,6 +1824,22 @@ FunctionScopeInfo *Sema::getEnclosingFunction() const { return nullptr; } +LambdaScopeInfo *Sema::getEnclosingLambda() const { + for (auto *Scope : llvm::reverse(FunctionScopes)) { + if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Scope)) { + if (LSI->Lambda && !LSI->Lambda->Encloses(CurContext)) { + // We have switched contexts due to template instantiation. + // FIXME: We should swap out the FunctionScopes during code synthesis + // so that we don't need to check for this. + assert(!CodeSynthesisContexts.empty()); + return nullptr; + } + return LSI; + } + } + return nullptr; +} + LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) { if (FunctionScopes.empty()) return nullptr; @@ -1812,6 +1862,7 @@ LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) { return CurLSI; } + // We have a generic lambda if we parsed auto parameters, or we have // an associated template parameter list. LambdaScopeInfo *Sema::getCurGenericLambda() { @@ -1934,11 +1985,9 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy, // member templates with defaults/deduction of template arguments, overloads // with default arguments, etc. if (IsMemExpr && !E.isTypeDependent()) { - bool Suppress = getDiagnostics().getSuppressAllDiagnostics(); - getDiagnostics().setSuppressAllDiagnostics(true); + Sema::TentativeAnalysisScope Trap(*this); ExprResult R = BuildCallToMemberFunction(nullptr, &E, SourceLocation(), None, SourceLocation()); - getDiagnostics().setSuppressAllDiagnostics(Suppress); if (R.isUsable()) { ZeroArgCallReturnTy = R.get()->getType(); return true; @@ -2112,10 +2161,12 @@ IdentifierInfo *Sema::getFloat128Identifier() const { } void Sema::PushCapturedRegionScope(Scope *S, CapturedDecl *CD, RecordDecl *RD, - CapturedRegionKind K) { - CapturingScopeInfo *CSI = new CapturedRegionScopeInfo( + CapturedRegionKind K, + unsigned OpenMPCaptureLevel) { + auto *CSI = new CapturedRegionScopeInfo( getDiagnostics(), S, CD, RD, CD->getContextParam(), K, - (getLangOpts().OpenMP && K == CR_OpenMP) ? getOpenMPNestingLevel() : 0); + (getLangOpts().OpenMP && K == CR_OpenMP) ? getOpenMPNestingLevel() : 0, + OpenMPCaptureLevel); CSI->ReturnType = Context.VoidTy; FunctionScopes.push_back(CSI); } diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index b6fbbbff91f5..9dbb93322b7d 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -1551,7 +1551,7 @@ Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, QualType BaseType = E->getBaseType(); if (E->isArrow()) - BaseType = BaseType->getAs<PointerType>()->getPointeeType(); + BaseType = BaseType->castAs<PointerType>()->getPointeeType(); AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(), Found, BaseType); @@ -1834,8 +1834,8 @@ Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc, return AR_accessible; CXXRecordDecl *BaseD, *DerivedD; - BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl()); - DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl()); + BaseD = cast<CXXRecordDecl>(Base->castAs<RecordType>()->getDecl()); + DerivedD = cast<CXXRecordDecl>(Derived->castAs<RecordType>()->getDecl()); AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD, Path.Access); diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index 8e9318847373..70186c966f8f 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -85,6 +85,123 @@ void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) { MSVtorDispAttr::CreateImplicit(Context, VtorDispStack.CurrentValue)); } +template <typename Attribute> +static void addGslOwnerPointerAttributeIfNotExisting(ASTContext &Context, + CXXRecordDecl *Record) { + if (Record->hasAttr<OwnerAttr>() || Record->hasAttr<PointerAttr>()) + return; + + for (Decl *Redecl : Record->redecls()) + Redecl->addAttr(Attribute::CreateImplicit(Context, /*DerefType=*/nullptr)); +} + +void Sema::inferGslPointerAttribute(NamedDecl *ND, + CXXRecordDecl *UnderlyingRecord) { + if (!UnderlyingRecord) + return; + + const auto *Parent = dyn_cast<CXXRecordDecl>(ND->getDeclContext()); + if (!Parent) + return; + + static llvm::StringSet<> Containers{ + "array", + "basic_string", + "deque", + "forward_list", + "vector", + "list", + "map", + "multiset", + "multimap", + "priority_queue", + "queue", + "set", + "stack", + "unordered_set", + "unordered_map", + "unordered_multiset", + "unordered_multimap", + }; + + static llvm::StringSet<> Iterators{"iterator", "const_iterator", + "reverse_iterator", + "const_reverse_iterator"}; + + if (Parent->isInStdNamespace() && Iterators.count(ND->getName()) && + Containers.count(Parent->getName())) + addGslOwnerPointerAttributeIfNotExisting<PointerAttr>(Context, + UnderlyingRecord); +} + +void Sema::inferGslPointerAttribute(TypedefNameDecl *TD) { + + QualType Canonical = TD->getUnderlyingType().getCanonicalType(); + + CXXRecordDecl *RD = Canonical->getAsCXXRecordDecl(); + if (!RD) { + if (auto *TST = + dyn_cast<TemplateSpecializationType>(Canonical.getTypePtr())) { + + RD = dyn_cast_or_null<CXXRecordDecl>( + TST->getTemplateName().getAsTemplateDecl()->getTemplatedDecl()); + } + } + + inferGslPointerAttribute(TD, RD); +} + +void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) { + static llvm::StringSet<> StdOwners{ + "any", + "array", + "basic_regex", + "basic_string", + "deque", + "forward_list", + "vector", + "list", + "map", + "multiset", + "multimap", + "optional", + "priority_queue", + "queue", + "set", + "stack", + "unique_ptr", + "unordered_set", + "unordered_map", + "unordered_multiset", + "unordered_multimap", + "variant", + }; + static llvm::StringSet<> StdPointers{ + "basic_string_view", + "reference_wrapper", + "regex_iterator", + }; + + if (!Record->getIdentifier()) + return; + + // Handle classes that directly appear in std namespace. + if (Record->isInStdNamespace()) { + if (Record->hasAttr<OwnerAttr>() || Record->hasAttr<PointerAttr>()) + return; + + if (StdOwners.count(Record->getName())) + addGslOwnerPointerAttributeIfNotExisting<OwnerAttr>(Context, Record); + else if (StdPointers.count(Record->getName())) + addGslOwnerPointerAttributeIfNotExisting<PointerAttr>(Context, Record); + + return; + } + + // Handle nested classes that could be a gsl::Pointer. + inferGslPointerAttribute(Record, Record); +} + void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, SourceLocation PragmaLoc) { PragmaMsStackAction Action = Sema::PSK_Reset; @@ -149,6 +266,9 @@ void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionA case PragmaClangSectionKind::PCSK_Rodata: CSec = &PragmaClangRodataSection; break; + case PragmaClangSectionKind::PCSK_Relro: + CSec = &PragmaClangRelroSection; + break; case PragmaClangSectionKind::PCSK_Text: CSec = &PragmaClangTextSection; break; @@ -454,12 +574,15 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope, if (VD->isUsed()) Diag(PragmaLoc, diag::warn_used_but_marked_unused) << Name; - VD->addAttr(UnusedAttr::CreateImplicit(Context, UnusedAttr::GNU_unused, - IdTok.getLocation())); + VD->addAttr(UnusedAttr::CreateImplicit(Context, IdTok.getLocation(), + AttributeCommonInfo::AS_Pragma, + UnusedAttr::GNU_unused)); } void Sema::AddCFAuditedAttribute(Decl *D) { - SourceLocation Loc = PP.getPragmaARCCFCodeAuditedLoc(); + IdentifierInfo *Ident; + SourceLocation Loc; + std::tie(Ident, Loc) = PP.getPragmaARCCFCodeAuditedInfo(); if (!Loc.isValid()) return; // Don't add a redundant or conflicting attribute. @@ -467,7 +590,9 @@ void Sema::AddCFAuditedAttribute(Decl *D) { D->hasAttr<CFUnknownTransferAttr>()) return; - D->addAttr(CFAuditedTransferAttr::CreateImplicit(Context, Loc)); + AttributeCommonInfo Info(Ident, SourceRange(Loc), + AttributeCommonInfo::AS_Pragma); + D->addAttr(CFAuditedTransferAttr::CreateImplicit(Context, Info)); } namespace { @@ -618,7 +743,7 @@ void Sema::ActOnPragmaAttributeAttribute( if (!Rules.empty()) { auto Diagnostic = Diag(PragmaLoc, diag::err_pragma_attribute_invalid_matchers) - << Attribute.getName(); + << Attribute; SmallVector<attr::SubjectMatchRule, 2> ExtraRules; for (const auto &Rule : Rules) { ExtraRules.push_back(attr::SubjectMatchRule(Rule.first)); diff --git a/lib/Sema/SemaCUDA.cpp b/lib/Sema/SemaCUDA.cpp index 203c09c57112..d0ddfd040c9c 100644 --- a/lib/Sema/SemaCUDA.cpp +++ b/lib/Sema/SemaCUDA.cpp @@ -267,6 +267,18 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, CXXMethodDecl *MemberDecl, bool ConstRHS, bool Diagnose) { + // If the defaulted special member is defined lexically outside of its + // owning class, or the special member already has explicit device or host + // attributes, do not infer. + bool InClass = MemberDecl->getLexicalParent() == MemberDecl->getParent(); + bool HasH = MemberDecl->hasAttr<CUDAHostAttr>(); + bool HasD = MemberDecl->hasAttr<CUDADeviceAttr>(); + bool HasExplicitAttr = + (HasD && !MemberDecl->getAttr<CUDADeviceAttr>()->isImplicit()) || + (HasH && !MemberDecl->getAttr<CUDAHostAttr>()->isImplicit()); + if (!InClass || HasExplicitAttr) + return false; + llvm::Optional<CUDAFunctionTarget> InferredTarget; // We're going to invoke special member lookup; mark that these special @@ -371,21 +383,23 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, } } + + // If no target was inferred, mark this member as __host__ __device__; + // it's the least restrictive option that can be invoked from any target. + bool NeedsH = true, NeedsD = true; if (InferredTarget.hasValue()) { - if (InferredTarget.getValue() == CFT_Device) { - MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context)); - } else if (InferredTarget.getValue() == CFT_Host) { - MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context)); - } else { - MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context)); - MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context)); - } - } else { - // If no target was inferred, mark this member as __host__ __device__; - // it's the least restrictive option that can be invoked from any target. + if (InferredTarget.getValue() == CFT_Device) + NeedsH = false; + else if (InferredTarget.getValue() == CFT_Host) + NeedsD = false; + } + + // We either setting attributes first time, or the inferred ones must match + // previously set ones. + if (NeedsD && !HasD) MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context)); + if (NeedsH && !HasH) MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context)); - } return false; } @@ -586,40 +600,6 @@ void Sema::maybeAddCUDAHostDeviceAttrs(FunctionDecl *NewD, NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context)); } -// Do we know that we will eventually codegen the given function? -static bool IsKnownEmitted(Sema &S, FunctionDecl *FD) { - // Templates are emitted when they're instantiated. - if (FD->isDependentContext()) - return false; - - // When compiling for device, host functions are never emitted. Similarly, - // when compiling for host, device and global functions are never emitted. - // (Technically, we do emit a host-side stub for global functions, but this - // doesn't count for our purposes here.) - Sema::CUDAFunctionTarget T = S.IdentifyCUDATarget(FD); - if (S.getLangOpts().CUDAIsDevice && T == Sema::CFT_Host) - return false; - if (!S.getLangOpts().CUDAIsDevice && - (T == Sema::CFT_Device || T == Sema::CFT_Global)) - return false; - - // Check whether this function is externally visible -- if so, it's - // known-emitted. - // - // We have to check the GVA linkage of the function's *definition* -- if we - // only have a declaration, we don't know whether or not the function will be - // emitted, because (say) the definition could include "inline". - FunctionDecl *Def = FD->getDefinition(); - - if (Def && - !isDiscardableGVALinkage(S.getASTContext().GetGVALinkageForFunction(Def))) - return true; - - // Otherwise, the function is known-emitted if it's in our set of - // known-emitted functions. - return S.DeviceKnownEmittedFns.count(FD) > 0; -} - Sema::DeviceDiagBuilder Sema::CUDADiagIfDeviceCode(SourceLocation Loc, unsigned DiagID) { assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); @@ -633,7 +613,8 @@ Sema::DeviceDiagBuilder Sema::CUDADiagIfDeviceCode(SourceLocation Loc, // device code if we're compiling for device. Defer any errors in device // mode until the function is known-emitted. if (getLangOpts().CUDAIsDevice) { - return IsKnownEmitted(*this, dyn_cast<FunctionDecl>(CurContext)) + return (getEmissionStatus(cast<FunctionDecl>(CurContext)) == + FunctionEmissionStatus::Emitted) ? DeviceDiagBuilder::K_ImmediateWithCallStack : DeviceDiagBuilder::K_Deferred; } @@ -661,7 +642,8 @@ Sema::DeviceDiagBuilder Sema::CUDADiagIfHostCode(SourceLocation Loc, if (getLangOpts().CUDAIsDevice) return DeviceDiagBuilder::K_Nop; - return IsKnownEmitted(*this, dyn_cast<FunctionDecl>(CurContext)) + return (getEmissionStatus(cast<FunctionDecl>(CurContext)) == + FunctionEmissionStatus::Emitted) ? DeviceDiagBuilder::K_ImmediateWithCallStack : DeviceDiagBuilder::K_Deferred; default: @@ -688,12 +670,16 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) { // If the caller is known-emitted, mark the callee as known-emitted. // Otherwise, mark the call in our call graph so we can traverse it later. - bool CallerKnownEmitted = IsKnownEmitted(*this, Caller); + bool CallerKnownEmitted = + getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted; if (CallerKnownEmitted) { // Host-side references to a __global__ function refer to the stub, so the // function itself is never emitted and therefore should not be marked. - if (getLangOpts().CUDAIsDevice || IdentifyCUDATarget(Callee) != CFT_Global) - markKnownEmitted(*this, Caller, Callee, Loc, IsKnownEmitted); + if (!shouldIgnoreInHostDeviceCheck(Callee)) + markKnownEmitted( + *this, Caller, Callee, Loc, [](Sema &S, FunctionDecl *FD) { + return S.getEmissionStatus(FD) == FunctionEmissionStatus::Emitted; + }); } else { // If we have // host fn calls kernel fn calls host+device, @@ -701,7 +687,7 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) { // omitting at the call to the kernel from the callgraph. This ensures // that, when compiling for host, only HD functions actually called from the // host get marked as known-emitted. - if (getLangOpts().CUDAIsDevice || IdentifyCUDATarget(Callee) != CFT_Global) + if (!shouldIgnoreInHostDeviceCheck(Callee)) DeviceCallGraph[Caller].insert({Callee, Loc}); } @@ -806,7 +792,8 @@ void Sema::inheritCUDATargetAttrs(FunctionDecl *FD, std::string Sema::getCudaConfigureFuncName() const { if (getLangOpts().HIP) - return "hipConfigureCall"; + return getLangOpts().HIPUseNewLaunchAPI ? "__hipPushCallConfiguration" + : "hipConfigureCall"; // New CUDA kernel launch sequence. if (CudaFeatureEnabled(Context.getTargetInfo().getSDKVersion(), diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index c473856f0b07..a4421d2b68af 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -440,7 +440,7 @@ public: } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<NestedNameSpecifierValidatorCCC>(*this); + return std::make_unique<NestedNameSpecifierValidatorCCC>(*this); } private: diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index f184eda2f273..0ebb5c68f7c2 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -1304,6 +1304,7 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, bool DerivedToBase; bool ObjCConversion; bool ObjCLifetimeConversion; + bool FunctionConversion; QualType FromType = SrcExpr->getType(); QualType ToType = R->getPointeeType(); if (CStyle) { @@ -1313,7 +1314,7 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, Sema::ReferenceCompareResult RefResult = Self.CompareReferenceRelationship( SrcExpr->getBeginLoc(), ToType, FromType, DerivedToBase, ObjCConversion, - ObjCLifetimeConversion); + ObjCLifetimeConversion, FunctionConversion); if (RefResult != Sema::Ref_Compatible) { if (CStyle || RefResult == Sema::Ref_Incompatible) return TC_NotApplicable; @@ -2799,6 +2800,15 @@ void CastOperation::CheckCStyleCast() { void CastOperation::CheckBuiltinBitCast() { QualType SrcType = SrcExpr.get()->getType(); + + if (Self.RequireCompleteType(OpRange.getBegin(), DestType, + diag::err_typecheck_cast_to_incomplete) || + Self.RequireCompleteType(OpRange.getBegin(), SrcType, + diag::err_incomplete_type)) { + SrcExpr = ExprError(); + return; + } + if (SrcExpr.get()->isRValue()) SrcExpr = Self.CreateMaterializeTemporaryExpr(SrcType, SrcExpr.get(), /*IsLValueReference=*/false); @@ -2826,11 +2836,6 @@ void CastOperation::CheckBuiltinBitCast() { return; } - if (Self.Context.hasSameUnqualifiedType(DestType, SrcType)) { - Kind = CK_NoOp; - return; - } - Kind = CK_LValueToRValueBitCast; } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index f9f82cdeef43..dca81d1d275f 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -191,7 +191,7 @@ static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) { return false; } -/// Check the number of arguments, and set the result type to +/// Check the number of arguments and set the result type to /// the argument type. static bool SemaBuiltinPreserveAI(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 1)) @@ -484,7 +484,7 @@ static bool checkOpenCLBlockArgs(Sema &S, Expr *BlockArg) { const BlockPointerType *BPT = cast<BlockPointerType>(BlockArg->getType().getCanonicalType()); ArrayRef<QualType> Params = - BPT->getPointeeType()->getAs<FunctionProtoType>()->getParamTypes(); + BPT->getPointeeType()->castAs<FunctionProtoType>()->getParamTypes(); unsigned ArgCounter = 0; bool IllegalParams = false; // Iterate through the block parameters until either one is found that is not @@ -583,7 +583,7 @@ static bool checkOpenCLEnqueueVariadicArgs(Sema &S, CallExpr *TheCall, const BlockPointerType *BPT = cast<BlockPointerType>(BlockArg->getType().getCanonicalType()); unsigned NumBlockParams = - BPT->getPointeeType()->getAs<FunctionProtoType>()->getNumParams(); + BPT->getPointeeType()->castAs<FunctionProtoType>()->getNumParams(); unsigned TotalNumArgs = TheCall->getNumArgs(); // For each argument passed to the block, a corresponding uint needs to @@ -629,7 +629,9 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { unsigned NumArgs = TheCall->getNumArgs(); if (NumArgs < 4) { - S.Diag(TheCall->getBeginLoc(), diag::err_typecheck_call_too_few_args); + S.Diag(TheCall->getBeginLoc(), + diag::err_typecheck_call_too_few_args_at_least) + << 0 << 4 << NumArgs; return true; } @@ -674,7 +676,7 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { // we have a block type, check the prototype const BlockPointerType *BPT = cast<BlockPointerType>(Arg3->getType().getCanonicalType()); - if (BPT->getPointeeType()->getAs<FunctionProtoType>()->getNumParams() > 0) { + if (BPT->getPointeeType()->castAs<FunctionProtoType>()->getNumParams() > 0) { S.Diag(Arg3->getBeginLoc(), diag::err_opencl_enqueue_kernel_blocks_no_args); return true; @@ -1179,6 +1181,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_alloca_with_align: if (SemaBuiltinAllocaWithAlign(TheCall)) return ExprError(); + LLVM_FALLTHROUGH; + case Builtin::BI__builtin_alloca: + Diag(TheCall->getBeginLoc(), diag::warn_alloca) + << TheCall->getDirectCallee(); break; case Builtin::BI__assume: case Builtin::BI__builtin_assume: @@ -1534,6 +1540,11 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; + case llvm::Triple::bpfeb: + case llvm::Triple::bpfel: + if (CheckBPFBuiltinFunctionCall(BuiltinID, TheCall)) + return ExprError(); + break; case llvm::Triple::hexagon: if (CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); @@ -1928,11 +1939,46 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, case AArch64::BI__builtin_arm_dmb: case AArch64::BI__builtin_arm_dsb: case AArch64::BI__builtin_arm_isb: l = 0; u = 15; break; + case AArch64::BI__builtin_arm_tcancel: l = 0; u = 65535; break; } return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); } +bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + assert(BuiltinID == BPF::BI__builtin_preserve_field_info && + "unexpected ARM builtin"); + + if (checkArgCount(*this, TheCall, 2)) + return true; + + // The first argument needs to be a record field access. + // If it is an array element access, we delay decision + // to BPF backend to check whether the access is a + // field access or not. + Expr *Arg = TheCall->getArg(0); + if (Arg->getType()->getAsPlaceholderType() || + (Arg->IgnoreParens()->getObjectKind() != OK_BitField && + !dyn_cast<MemberExpr>(Arg->IgnoreParens()) && + !dyn_cast<ArraySubscriptExpr>(Arg->IgnoreParens()))) { + Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_field) + << 1 << Arg->getSourceRange(); + return true; + } + + // The second argument needs to be a constant int + llvm::APSInt Value; + if (!TheCall->getArg(1)->isIntegerConstantExpr(Value, Context)) { + Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_const) + << 2 << Arg->getSourceRange(); + return true; + } + + TheCall->setType(Context.UnsignedIntTy); + return false; +} + bool Sema::CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) { struct BuiltinAndString { unsigned BuiltinID; @@ -3213,6 +3259,8 @@ bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case PPC::BI__builtin_altivec_crypto_vshasigmad: return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) || SemaBuiltinConstantArgRange(TheCall, 2, 0, 15); + case PPC::BI__builtin_altivec_dss: + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3); case PPC::BI__builtin_tbegin: case PPC::BI__builtin_tend: i = 0; l = 0; u = 1; break; case PPC::BI__builtin_tsr: i = 0; l = 0; u = 7; break; @@ -3222,6 +3270,11 @@ bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case PPC::BI__builtin_tabortdci: return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) || SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + case PPC::BI__builtin_altivec_dst: + case PPC::BI__builtin_altivec_dstt: + case PPC::BI__builtin_altivec_dstst: + case PPC::BI__builtin_altivec_dststt: + return SemaBuiltinConstantArgRange(TheCall, 2, 0, 3); case PPC::BI__builtin_vsx_xxpermdi: case PPC::BI__builtin_vsx_xxsldwi: return SemaBuiltinVSX(TheCall); @@ -3532,9 +3585,11 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { // Make sure rounding mode is either ROUND_CUR_DIRECTION or ROUND_NO_EXC bit // is set. If the intrinsic has rounding control(bits 1:0), make sure its only - // combined with ROUND_NO_EXC. + // combined with ROUND_NO_EXC. If the intrinsic does not have rounding + // control, allow ROUND_NO_EXC and ROUND_CUR_DIRECTION together. if (Result == 4/*ROUND_CUR_DIRECTION*/ || Result == 8/*ROUND_NO_EXC*/ || + (!HasRC && Result == 12/*ROUND_CUR_DIRECTION|ROUND_NO_EXC*/) || (HasRC && Result.getZExtValue() >= 8 && Result.getZExtValue() <= 11)) return false; @@ -4449,7 +4504,16 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op) { CallExpr *TheCall = cast<CallExpr>(TheCallResult.get()); DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); + MultiExprArg Args{TheCall->getArgs(), TheCall->getNumArgs()}; + return BuildAtomicExpr({TheCall->getBeginLoc(), TheCall->getEndLoc()}, + DRE->getSourceRange(), TheCall->getRParenLoc(), Args, + Op); +} +ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, + SourceLocation RParenLoc, MultiExprArg Args, + AtomicExpr::AtomicOp Op, + AtomicArgumentOrder ArgOrder) { // All the non-OpenCL operations take one of the following forms. // The OpenCL operations take the __c11 forms with one extra argument for // synchronization scope. @@ -4596,21 +4660,21 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, if (IsOpenCL && Op != AtomicExpr::AO__opencl_atomic_init) ++AdjustedNumArgs; // Check we have the right number of arguments. - if (TheCall->getNumArgs() < AdjustedNumArgs) { - Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args) - << 0 << AdjustedNumArgs << TheCall->getNumArgs() - << TheCall->getCallee()->getSourceRange(); + if (Args.size() < AdjustedNumArgs) { + Diag(CallRange.getEnd(), diag::err_typecheck_call_too_few_args) + << 0 << AdjustedNumArgs << static_cast<unsigned>(Args.size()) + << ExprRange; return ExprError(); - } else if (TheCall->getNumArgs() > AdjustedNumArgs) { - Diag(TheCall->getArg(AdjustedNumArgs)->getBeginLoc(), + } else if (Args.size() > AdjustedNumArgs) { + Diag(Args[AdjustedNumArgs]->getBeginLoc(), diag::err_typecheck_call_too_many_args) - << 0 << AdjustedNumArgs << TheCall->getNumArgs() - << TheCall->getCallee()->getSourceRange(); + << 0 << AdjustedNumArgs << static_cast<unsigned>(Args.size()) + << ExprRange; return ExprError(); } // Inspect the first argument of the atomic operation. - Expr *Ptr = TheCall->getArg(0); + Expr *Ptr = Args[0]; ExprResult ConvertedPtr = DefaultFunctionArrayLvalueConversion(Ptr); if (ConvertedPtr.isInvalid()) return ExprError(); @@ -4618,7 +4682,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, Ptr = ConvertedPtr.get(); const PointerType *pointerType = Ptr->getType()->getAs<PointerType>(); if (!pointerType) { - Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer) + Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -4628,21 +4692,21 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, QualType ValType = AtomTy; // 'C' if (IsC11) { if (!AtomTy->isAtomicType()) { - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_atomic) + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } if ((Form != Load && Form != LoadCopy && AtomTy.isConstQualified()) || AtomTy.getAddressSpace() == LangAS::opencl_constant) { - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_non_const_atomic) + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_non_const_atomic) << (AtomTy.isConstQualified() ? 0 : 1) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } - ValType = AtomTy->getAs<AtomicType>()->getValueType(); + ValType = AtomTy->castAs<AtomicType>()->getValueType(); } else if (Form != Load && Form != LoadCopy) { if (ValType.isConstQualified()) { - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_non_const_pointer) + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_non_const_pointer) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -4653,7 +4717,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // gcc does not enforce these rules for GNU atomics, but we do so for sanity. if (IsAddSub && !ValType->isIntegerType() && !ValType->isPointerType()) { - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_atomic_int_or_ptr) + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int_or_ptr) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -4661,12 +4725,12 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, const BuiltinType *BT = ValType->getAs<BuiltinType>(); if (!BT || (BT->getKind() != BuiltinType::Int && BT->getKind() != BuiltinType::UInt)) { - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_int32_or_ptr); + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_int32_or_ptr); return ExprError(); } } if (!IsAddSub && !IsMinMax && !ValType->isIntegerType()) { - Diag(DRE->getBeginLoc(), diag::err_atomic_op_bitwise_needs_atomic_int) + Diag(ExprRange.getBegin(), diag::err_atomic_op_bitwise_needs_atomic_int) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -4678,7 +4742,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, } else if (IsN && !ValType->isIntegerType() && !ValType->isPointerType()) { // For __atomic_*_n operations, the value type must be a scalar integral or // pointer type which is 1, 2, 4, 8 or 16 bytes in length. - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_atomic_int_or_ptr) + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int_or_ptr) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -4687,7 +4751,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, !AtomTy->isScalarType()) { // For GNU atomics, require a trivially-copyable type. This is not part of // the GNU atomics specification, but we enforce it for sanity. - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_trivial_copy) + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_trivial_copy) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -4703,7 +4767,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, case Qualifiers::OCL_Autoreleasing: // FIXME: Can this happen? By this point, ValType should be known // to be trivially copyable. - Diag(DRE->getBeginLoc(), diag::err_arc_atomic_ownership) + Diag(ExprRange.getBegin(), diag::err_arc_atomic_ownership) << ValType << Ptr->getSourceRange(); return ExprError(); } @@ -4730,19 +4794,56 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, IsPassedByAddress = true; } + SmallVector<Expr *, 5> APIOrderedArgs; + if (ArgOrder == Sema::AtomicArgumentOrder::AST) { + APIOrderedArgs.push_back(Args[0]); + switch (Form) { + case Init: + case Load: + APIOrderedArgs.push_back(Args[1]); // Val1/Order + break; + case LoadCopy: + case Copy: + case Arithmetic: + case Xchg: + APIOrderedArgs.push_back(Args[2]); // Val1 + APIOrderedArgs.push_back(Args[1]); // Order + break; + case GNUXchg: + APIOrderedArgs.push_back(Args[2]); // Val1 + APIOrderedArgs.push_back(Args[3]); // Val2 + APIOrderedArgs.push_back(Args[1]); // Order + break; + case C11CmpXchg: + APIOrderedArgs.push_back(Args[2]); // Val1 + APIOrderedArgs.push_back(Args[4]); // Val2 + APIOrderedArgs.push_back(Args[1]); // Order + APIOrderedArgs.push_back(Args[3]); // OrderFail + break; + case GNUCmpXchg: + APIOrderedArgs.push_back(Args[2]); // Val1 + APIOrderedArgs.push_back(Args[4]); // Val2 + APIOrderedArgs.push_back(Args[5]); // Weak + APIOrderedArgs.push_back(Args[1]); // Order + APIOrderedArgs.push_back(Args[3]); // OrderFail + break; + } + } else + APIOrderedArgs.append(Args.begin(), Args.end()); + // The first argument's non-CV pointer type is used to deduce the type of // subsequent arguments, except for: // - weak flag (always converted to bool) // - memory order (always converted to int) // - scope (always converted to int) - for (unsigned i = 0; i != TheCall->getNumArgs(); ++i) { + for (unsigned i = 0; i != APIOrderedArgs.size(); ++i) { QualType Ty; if (i < NumVals[Form] + 1) { switch (i) { case 0: // The first argument is always a pointer. It has a fixed type. // It is always dereferenced, a nullptr is undefined. - CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getBeginLoc()); + CheckNonNullArgument(*this, APIOrderedArgs[i], ExprRange.getBegin()); // Nothing else to do: we already know all we want about this pointer. continue; case 1: @@ -4754,16 +4855,18 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, if (Form == Init || (Form == Arithmetic && ValType->isIntegerType())) Ty = ValType; else if (Form == Copy || Form == Xchg) { - if (IsPassedByAddress) + if (IsPassedByAddress) { // The value pointer is always dereferenced, a nullptr is undefined. - CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getBeginLoc()); + CheckNonNullArgument(*this, APIOrderedArgs[i], + ExprRange.getBegin()); + } Ty = ByValType; } else if (Form == Arithmetic) Ty = Context.getPointerDiffType(); else { - Expr *ValArg = TheCall->getArg(i); + Expr *ValArg = APIOrderedArgs[i]; // The value pointer is always dereferenced, a nullptr is undefined. - CheckNonNullArgument(*this, ValArg, DRE->getBeginLoc()); + CheckNonNullArgument(*this, ValArg, ExprRange.getBegin()); LangAS AS = LangAS::Default; // Keep address space of non-atomic pointer type. if (const PointerType *PtrTy = @@ -4778,7 +4881,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // The third argument to compare_exchange / GNU exchange is the desired // value, either by-value (for the C11 and *_n variant) or as a pointer. if (IsPassedByAddress) - CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getBeginLoc()); + CheckNonNullArgument(*this, APIOrderedArgs[i], ExprRange.getBegin()); Ty = ByValType; break; case 3: @@ -4793,11 +4896,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, Ty, false); - ExprResult Arg = TheCall->getArg(i); + ExprResult Arg = APIOrderedArgs[i]; Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); if (Arg.isInvalid()) return true; - TheCall->setArg(i, Arg.get()); + APIOrderedArgs[i] = Arg.get(); } // Permute the arguments into a 'consistent' order. @@ -4806,36 +4909,36 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, switch (Form) { case Init: // Note, AtomicExpr::getVal1() has a special case for this atomic. - SubExprs.push_back(TheCall->getArg(1)); // Val1 + SubExprs.push_back(APIOrderedArgs[1]); // Val1 break; case Load: - SubExprs.push_back(TheCall->getArg(1)); // Order + SubExprs.push_back(APIOrderedArgs[1]); // Order break; case LoadCopy: case Copy: case Arithmetic: case Xchg: - SubExprs.push_back(TheCall->getArg(2)); // Order - SubExprs.push_back(TheCall->getArg(1)); // Val1 + SubExprs.push_back(APIOrderedArgs[2]); // Order + SubExprs.push_back(APIOrderedArgs[1]); // Val1 break; case GNUXchg: // Note, AtomicExpr::getVal2() has a special case for this atomic. - SubExprs.push_back(TheCall->getArg(3)); // Order - SubExprs.push_back(TheCall->getArg(1)); // Val1 - SubExprs.push_back(TheCall->getArg(2)); // Val2 + SubExprs.push_back(APIOrderedArgs[3]); // Order + SubExprs.push_back(APIOrderedArgs[1]); // Val1 + SubExprs.push_back(APIOrderedArgs[2]); // Val2 break; case C11CmpXchg: - SubExprs.push_back(TheCall->getArg(3)); // Order - SubExprs.push_back(TheCall->getArg(1)); // Val1 - SubExprs.push_back(TheCall->getArg(4)); // OrderFail - SubExprs.push_back(TheCall->getArg(2)); // Val2 + SubExprs.push_back(APIOrderedArgs[3]); // Order + SubExprs.push_back(APIOrderedArgs[1]); // Val1 + SubExprs.push_back(APIOrderedArgs[4]); // OrderFail + SubExprs.push_back(APIOrderedArgs[2]); // Val2 break; case GNUCmpXchg: - SubExprs.push_back(TheCall->getArg(4)); // Order - SubExprs.push_back(TheCall->getArg(1)); // Val1 - SubExprs.push_back(TheCall->getArg(5)); // OrderFail - SubExprs.push_back(TheCall->getArg(2)); // Val2 - SubExprs.push_back(TheCall->getArg(3)); // Weak + SubExprs.push_back(APIOrderedArgs[4]); // Order + SubExprs.push_back(APIOrderedArgs[1]); // Val1 + SubExprs.push_back(APIOrderedArgs[5]); // OrderFail + SubExprs.push_back(APIOrderedArgs[2]); // Val2 + SubExprs.push_back(APIOrderedArgs[3]); // Weak break; } @@ -4849,7 +4952,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, } if (auto ScopeModel = AtomicExpr::getScopeModel(Op)) { - auto *Scope = TheCall->getArg(TheCall->getNumArgs() - 1); + auto *Scope = Args[Args.size() - 1]; llvm::APSInt Result(32); if (Scope->isIntegerConstantExpr(Result, Context) && !ScopeModel->isValid(Result.getZExtValue())) { @@ -4859,9 +4962,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, SubExprs.push_back(Scope); } - AtomicExpr *AE = - new (Context) AtomicExpr(TheCall->getCallee()->getBeginLoc(), SubExprs, - ResultType, Op, TheCall->getRParenLoc()); + AtomicExpr *AE = new (Context) + AtomicExpr(ExprRange.getBegin(), SubExprs, ResultType, Op, RParenLoc); if ((Op == AtomicExpr::AO__c11_atomic_load || Op == AtomicExpr::AO__c11_atomic_store || @@ -5410,7 +5512,7 @@ static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) { if (IsX64 || IsAArch64) { CallingConv CC = CC_C; if (const FunctionDecl *FD = S.getCurFunctionDecl()) - CC = FD->getType()->getAs<FunctionType>()->getCallConv(); + CC = FD->getType()->castAs<FunctionType>()->getCallConv(); if (IsMSVAStart) { // Don't allow this in System V ABI functions. if (CC == CC_X86_64SysV || (!IsWindows && CC != CC_Win64)) @@ -5540,7 +5642,7 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { return false; if (!Type->isEnumeralType()) return true; - const EnumDecl *ED = Type->getAs<EnumType>()->getDecl(); + const EnumDecl *ED = Type->castAs<EnumType>()->getDecl(); return !(ED && Context.typesAreCompatible(ED->getPromotionType(), Type)); }()) { @@ -5780,7 +5882,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { << SourceRange(TheCall->getArg(0)->getBeginLoc(), TheCall->getArg(1)->getEndLoc())); - numElements = LHSType->getAs<VectorType>()->getNumElements(); + numElements = LHSType->castAs<VectorType>()->getNumElements(); unsigned numResElements = TheCall->getNumArgs() - 2; // Check to see if we have a call with 2 vector arguments, the unary shuffle @@ -5788,7 +5890,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { // same number of elts as lhs. if (TheCall->getNumArgs() == 2) { if (!RHSType->hasIntegerRepresentation() || - RHSType->getAs<VectorType>()->getNumElements() != numElements) + RHSType->castAs<VectorType>()->getNumElements() != numElements) return ExprError(Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector) << TheCall->getDirectCallee() @@ -5801,7 +5903,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { << SourceRange(TheCall->getArg(0)->getBeginLoc(), TheCall->getArg(1)->getEndLoc())); } else if (numElements != numResElements) { - QualType eltType = LHSType->getAs<VectorType>()->getElementType(); + QualType eltType = LHSType->castAs<VectorType>()->getElementType(); resType = Context.getVectorType(eltType, numResElements, VectorType::GenericVector); } @@ -5858,8 +5960,8 @@ ExprResult Sema::SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, diag::err_convertvector_non_vector_type)); if (!SrcTy->isDependentType() && !DstTy->isDependentType()) { - unsigned SrcElts = SrcTy->getAs<VectorType>()->getNumElements(); - unsigned DstElts = DstTy->getAs<VectorType>()->getNumElements(); + unsigned SrcElts = SrcTy->castAs<VectorType>()->getNumElements(); + unsigned DstElts = DstTy->castAs<VectorType>()->getNumElements(); if (SrcElts != DstElts) return ExprError(Diag(BuiltinLoc, diag::err_convertvector_incompatible_vector) @@ -5961,6 +6063,12 @@ bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { if (!Result.isPowerOf2()) return Diag(TheCall->getBeginLoc(), diag::err_alignment_not_power_of_two) << Arg->getSourceRange(); + + // Alignment calculations can wrap around if it's greater than 2**29. + unsigned MaximumAlignment = 536870912; + if (Result > MaximumAlignment) + Diag(TheCall->getBeginLoc(), diag::warn_assume_aligned_too_great) + << Arg->getSourceRange() << MaximumAlignment; } if (NumArgs > 2) { @@ -6570,7 +6678,8 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, bool inFunctionCall, Sema::VariadicCallType CallType, llvm::SmallBitVector &CheckedVarArgs, - UncoveredArgHandler &UncoveredArg); + UncoveredArgHandler &UncoveredArg, + bool IgnoreStringsWithoutSpecifiers); // Determine if an expression is a string literal or constant string. // If this function returns false on the arguments to a function expecting a @@ -6583,7 +6692,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, Sema::VariadicCallType CallType, bool InFunctionCall, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg, - llvm::APSInt Offset) { + llvm::APSInt Offset, + bool IgnoreStringsWithoutSpecifiers = false) { if (S.isConstantEvaluated()) return SLCT_NotALiteral; tryAgain: @@ -6634,17 +6744,17 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, Left = checkFormatStringExpr(S, C->getTrueExpr(), Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, - CheckedVarArgs, UncoveredArg, Offset); + CheckedVarArgs, UncoveredArg, Offset, + IgnoreStringsWithoutSpecifiers); if (Left == SLCT_NotALiteral || !CheckRight) { return Left; } } - StringLiteralCheckType Right = - checkFormatStringExpr(S, C->getFalseExpr(), Args, - HasVAListArg, format_idx, firstDataArg, - Type, CallType, InFunctionCall, CheckedVarArgs, - UncoveredArg, Offset); + StringLiteralCheckType Right = checkFormatStringExpr( + S, C->getFalseExpr(), Args, HasVAListArg, format_idx, firstDataArg, + Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset, + IgnoreStringsWithoutSpecifiers); return (CheckLeft && Left < Right) ? Left : Right; } @@ -6748,7 +6858,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex()); StringLiteralCheckType Result = checkFormatStringExpr( S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, - CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset); + CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset, + IgnoreStringsWithoutSpecifiers); if (IsFirst) { CommonResult = Result; IsFirst = false; @@ -6766,7 +6877,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs, - UncoveredArg, Offset); + UncoveredArg, Offset, + IgnoreStringsWithoutSpecifiers); } } } @@ -6775,12 +6887,28 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, } case Stmt::ObjCMessageExprClass: { const auto *ME = cast<ObjCMessageExpr>(E); - if (const auto *ND = ME->getMethodDecl()) { - if (const auto *FA = ND->getAttr<FormatArgAttr>()) { + if (const auto *MD = ME->getMethodDecl()) { + if (const auto *FA = MD->getAttr<FormatArgAttr>()) { + // As a special case heuristic, if we're using the method -[NSBundle + // localizedStringForKey:value:table:], ignore any key strings that lack + // format specifiers. The idea is that if the key doesn't have any + // format specifiers then its probably just a key to map to the + // localized strings. If it does have format specifiers though, then its + // likely that the text of the key is the format string in the + // programmer's language, and should be checked. + const ObjCInterfaceDecl *IFace; + if (MD->isInstanceMethod() && (IFace = MD->getClassInterface()) && + IFace->getIdentifier()->isStr("NSBundle") && + MD->getSelector().isKeywordSelector( + {"localizedStringForKey", "value", "table"})) { + IgnoreStringsWithoutSpecifiers = true; + } + const Expr *Arg = ME->getArg(FA->getFormatIdx().getASTIndex()); return checkFormatStringExpr( S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, - CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset); + CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset, + IgnoreStringsWithoutSpecifiers); } } @@ -6804,7 +6932,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, FormatStringLiteral FStr(StrE, Offset.sextOrTrunc(64).getSExtValue()); CheckFormatString(S, &FStr, E, Args, HasVAListArg, format_idx, firstDataArg, Type, InFunctionCall, CallType, - CheckedVarArgs, UncoveredArg); + CheckedVarArgs, UncoveredArg, + IgnoreStringsWithoutSpecifiers); return SLCT_CheckedLiteral; } @@ -8072,9 +8201,23 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, ExprTy = TET->getUnderlyingExpr()->getType(); } - const analyze_printf::ArgType::MatchKind Match = - AT.matchesType(S.Context, ExprTy); - bool Pedantic = Match == analyze_printf::ArgType::NoMatchPedantic; + // Diagnose attempts to print a boolean value as a character. Unlike other + // -Wformat diagnostics, this is fine from a type perspective, but it still + // doesn't make sense. + if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::cArg && + E->isKnownToHaveBooleanValue()) { + const CharSourceRange &CSR = + getSpecifierRange(StartSpecifier, SpecifierLen); + SmallString<4> FSString; + llvm::raw_svector_ostream os(FSString); + FS.toString(os); + EmitFormatDiagnostic(S.PDiag(diag::warn_format_bool_as_character) + << FSString, + E->getExprLoc(), false, CSR); + return true; + } + + analyze_printf::ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy); if (Match == analyze_printf::ArgType::Match) return true; @@ -8093,9 +8236,14 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // function. if (ICE->getType() == S.Context.IntTy || ICE->getType() == S.Context.UnsignedIntTy) { - // All further checking is done on the subexpression. - if (AT.matchesType(S.Context, ExprTy)) + // All further checking is done on the subexpression + const analyze_printf::ArgType::MatchKind ImplicitMatch = + AT.matchesType(S.Context, ExprTy); + if (ImplicitMatch == analyze_printf::ArgType::Match) return true; + if (ImplicitMatch == ArgType::NoMatchPedantic || + ImplicitMatch == ArgType::NoMatchTypeConfusion) + Match = ImplicitMatch; } } } else if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E)) { @@ -8157,7 +8305,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, if ((CastTyName == "NSInteger" || CastTyName == "NSUInteger") && (AT.isSizeT() || AT.isPtrdiffT()) && AT.matchesType(S.Context, CastTy)) - Pedantic = true; + Match = ArgType::NoMatchPedantic; IntendedTy = CastTy; ShouldNotPrintDirectly = true; } @@ -8177,10 +8325,20 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen); if (IntendedTy == ExprTy && !ShouldNotPrintDirectly) { - unsigned Diag = - Pedantic - ? diag::warn_format_conversion_argument_type_mismatch_pedantic - : diag::warn_format_conversion_argument_type_mismatch; + unsigned Diag; + switch (Match) { + case ArgType::Match: llvm_unreachable("expected non-matching"); + case ArgType::NoMatchPedantic: + Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; + break; + case ArgType::NoMatchTypeConfusion: + Diag = diag::warn_format_conversion_argument_type_mismatch_confusion; + break; + case ArgType::NoMatch: + Diag = diag::warn_format_conversion_argument_type_mismatch; + break; + } + // In this case, the specifier is wrong and should be changed to match // the argument. EmitFormatDiagnostic(S.PDiag(Diag) @@ -8236,7 +8394,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, Name = TypedefTy->getDecl()->getName(); else Name = CastTyName; - unsigned Diag = Pedantic + unsigned Diag = Match == ArgType::NoMatchPedantic ? diag::warn_format_argument_needs_cast_pedantic : diag::warn_format_argument_needs_cast; EmitFormatDiagnostic(S.PDiag(Diag) << Name << IntendedTy << IsEnum @@ -8263,10 +8421,19 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, switch (S.isValidVarArgType(ExprTy)) { case Sema::VAK_Valid: case Sema::VAK_ValidInCXX11: { - unsigned Diag = - Pedantic - ? diag::warn_format_conversion_argument_type_mismatch_pedantic - : diag::warn_format_conversion_argument_type_mismatch; + unsigned Diag; + switch (Match) { + case ArgType::Match: llvm_unreachable("expected non-matching"); + case ArgType::NoMatchPedantic: + Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; + break; + case ArgType::NoMatchTypeConfusion: + Diag = diag::warn_format_conversion_argument_type_mismatch_confusion; + break; + case ArgType::NoMatch: + Diag = diag::warn_format_conversion_argument_type_mismatch; + break; + } EmitFormatDiagnostic( S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy @@ -8495,7 +8662,8 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, bool inFunctionCall, Sema::VariadicCallType CallType, llvm::SmallBitVector &CheckedVarArgs, - UncoveredArgHandler &UncoveredArg) { + UncoveredArgHandler &UncoveredArg, + bool IgnoreStringsWithoutSpecifiers) { // CHECK: is the format string a wide literal? if (!FExpr->isAscii() && !FExpr->isUTF8()) { CheckFormatHandler::EmitFormatDiagnostic( @@ -8516,6 +8684,11 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size()); const unsigned numDataArgs = Args.size() - firstDataArg; + if (IgnoreStringsWithoutSpecifiers && + !analyze_format_string::parseFormatStringHasFormattingSpecifiers( + Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo())) + return; + // Emit a warning if the string literal is truncated and does not contain an // embedded null character. if (TypeSize <= StrRef.size() && @@ -10195,7 +10368,8 @@ static bool IsSameFloatAfterCast(const APValue &value, IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt)); } -static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC); +static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC, + bool IsListInit = false); static bool IsEnumConstOrFromMacro(Sema &S, Expr *E) { // Suppress cases where we are comparing against an enum constant. @@ -10627,7 +10801,7 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, return false; if (BitfieldType->isEnumeralType()) { - EnumDecl *BitfieldEnumDecl = BitfieldType->getAs<EnumType>()->getDecl(); + EnumDecl *BitfieldEnumDecl = BitfieldType->castAs<EnumType>()->getDecl(); // If the underlying enum type was not explicitly specified as an unsigned // type and the enum contain only positive values, MSVC++ will cause an // inconsistency by storing this as a signed type. @@ -10792,6 +10966,26 @@ static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, pruneControlFlow); } +static bool isObjCSignedCharBool(Sema &S, QualType Ty) { + return Ty->isSpecificBuiltinType(BuiltinType::SChar) && + S.getLangOpts().ObjC && S.NSAPIObj->isObjCBOOLType(Ty); +} + +static void adornObjCBoolConversionDiagWithTernaryFixit( + Sema &S, Expr *SourceExpr, const Sema::SemaDiagnosticBuilder &Builder) { + Expr *Ignored = SourceExpr->IgnoreImplicit(); + if (const auto *OVE = dyn_cast<OpaqueValueExpr>(Ignored)) + Ignored = OVE->getSourceExpr(); + bool NeedsParens = isa<AbstractConditionalOperator>(Ignored) || + isa<BinaryOperator>(Ignored) || + isa<CXXOperatorCallExpr>(Ignored); + SourceLocation EndLoc = S.getLocForEndOfToken(SourceExpr->getEndLoc()); + if (NeedsParens) + Builder << FixItHint::CreateInsertion(SourceExpr->getBeginLoc(), "(") + << FixItHint::CreateInsertion(EndLoc, ")"); + Builder << FixItHint::CreateInsertion(EndLoc, " ? YES : NO"); +} + /// Diagnose an implicit cast from a floating point value to an integer value. static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext) { @@ -10811,6 +11005,13 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, bool IsConstant = E->EvaluateAsFloat(Value, S.Context, Expr::SE_AllowSideEffects); if (!IsConstant) { + if (isObjCSignedCharBool(S, T)) { + return adornObjCBoolConversionDiagWithTernaryFixit( + S, E, + S.Diag(CContext, diag::warn_impcast_float_to_objc_signed_char_bool) + << E->getType()); + } + return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer, PruneWarnings); } @@ -10822,6 +11023,23 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, llvm::APFloat::opStatus Result = Value.convertToInteger( IntegerValue, llvm::APFloat::rmTowardZero, &isExact); + // FIXME: Force the precision of the source value down so we don't print + // digits which are usually useless (we don't really care here if we + // truncate a digit by accident in edge cases). Ideally, APFloat::toString + // would automatically print the shortest representation, but it's a bit + // tricky to implement. + SmallString<16> PrettySourceValue; + unsigned precision = llvm::APFloat::semanticsPrecision(Value.getSemantics()); + precision = (precision * 59 + 195) / 196; + Value.toString(PrettySourceValue, precision); + + if (isObjCSignedCharBool(S, T) && IntegerValue != 0 && IntegerValue != 1) { + return adornObjCBoolConversionDiagWithTernaryFixit( + S, E, + S.Diag(CContext, diag::warn_impcast_constant_value_to_objc_bool) + << PrettySourceValue); + } + if (Result == llvm::APFloat::opOK && isExact) { if (IsLiteral) return; return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer, @@ -10865,16 +11083,6 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, DiagID = diag::warn_impcast_float_to_integer; } - // FIXME: Force the precision of the source value down so we don't print - // digits which are usually useless (we don't really care here if we - // truncate a digit by accident in edge cases). Ideally, APFloat::toString - // would automatically print the shortest representation, but it's a bit - // tricky to implement. - SmallString<16> PrettySourceValue; - unsigned precision = llvm::APFloat::semanticsPrecision(Value.getSemantics()); - precision = (precision * 59 + 195) / 196; - Value.toString(PrettySourceValue, precision); - SmallString<16> PrettyTargetValue; if (IsBool) PrettyTargetValue = Value.isZero() ? "false" : "true"; @@ -11151,14 +11359,85 @@ static bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T, return true; } -static bool isObjCSignedCharBool(Sema &S, QualType Ty) { - return Ty->isSpecificBuiltinType(BuiltinType::SChar) && - S.getLangOpts().ObjC && S.NSAPIObj->isObjCBOOLType(Ty); +static const IntegerLiteral *getIntegerLiteral(Expr *E) { + const auto *IL = dyn_cast<IntegerLiteral>(E); + if (!IL) { + if (auto *UO = dyn_cast<UnaryOperator>(E)) { + if (UO->getOpcode() == UO_Minus) + return dyn_cast<IntegerLiteral>(UO->getSubExpr()); + } + } + + return IL; } -static void -CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, - bool *ICContext = nullptr) { +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(); + + if (const auto *BO = dyn_cast<BinaryOperator>(E)) { + BinaryOperator::Opcode Opc = BO->getOpcode(); + Expr::EvalResult Result; + // Do not diagnose unsigned shifts. + if (Opc == BO_Shl) { + const auto *LHS = getIntegerLiteral(BO->getLHS()); + const auto *RHS = getIntegerLiteral(BO->getRHS()); + if (LHS && LHS->getValue() == 0) + S.Diag(ExprLoc, diag::warn_left_shift_always) << 0; + else if (!E->isValueDependent() && LHS && RHS && + RHS->getValue().isNonNegative() && + E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects)) + S.Diag(ExprLoc, diag::warn_left_shift_always) + << (Result.Val.getInt() != 0); + else if (E->getType()->isSignedIntegerType()) + S.Diag(ExprLoc, diag::warn_left_shift_in_bool_context) << E; + } + } + + if (const auto *CO = dyn_cast<ConditionalOperator>(E)) { + const auto *LHS = getIntegerLiteral(CO->getTrueExpr()); + const auto *RHS = getIntegerLiteral(CO->getFalseExpr()); + if (!LHS || !RHS) + return; + if ((LHS->getValue() == 0 || LHS->getValue() == 1) && + (RHS->getValue() == 0 || RHS->getValue() == 1)) + // Do not diagnose common idioms. + return; + if (LHS->getValue() != 0 && RHS->getValue() != 0) + S.Diag(ExprLoc, diag::warn_integer_constants_in_conditional_always_true); + } +} + +static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, + SourceLocation CC, + bool *ICContext = nullptr, + bool IsListInit = false) { if (E->isTypeDependent() || E->isValueDependent()) return; const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr(); @@ -11205,19 +11484,13 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, if (isObjCSignedCharBool(S, T) && Source->isIntegralType(S.Context)) { Expr::EvalResult Result; if (E->EvaluateAsInt(Result, S.getASTContext(), - Expr::SE_AllowSideEffects) && - Result.Val.getInt() != 1 && Result.Val.getInt() != 0) { - auto Builder = S.Diag(CC, diag::warn_impcast_constant_int_to_objc_bool) - << Result.Val.getInt().toString(10); - Expr *Ignored = E->IgnoreImplicit(); - bool NeedsParens = isa<AbstractConditionalOperator>(Ignored) || - isa<BinaryOperator>(Ignored) || - isa<CXXOperatorCallExpr>(Ignored); - SourceLocation EndLoc = S.getLocForEndOfToken(E->getEndLoc()); - if (NeedsParens) - Builder << FixItHint::CreateInsertion(E->getBeginLoc(), "(") - << FixItHint::CreateInsertion(EndLoc, ")"); - Builder << FixItHint::CreateInsertion(EndLoc, " ? YES : NO"); + Expr::SE_AllowSideEffects)) { + if (Result.Val.getInt() != 1 && Result.Val.getInt() != 0) { + adornObjCBoolConversionDiagWithTernaryFixit( + S, E, + S.Diag(CC, diag::warn_impcast_constant_value_to_objc_bool) + << Result.Val.getInt().toString(10)); + } return; } } @@ -11400,10 +11673,61 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, } } + // If we are casting an integer type to a floating point type without + // initialization-list syntax, we might lose accuracy if the floating + // point type has a narrower significand than the integer type. + if (SourceBT && TargetBT && SourceBT->isIntegerType() && + TargetBT->isFloatingType() && !IsListInit) { + // Determine the number of precision bits in the source integer type. + IntRange SourceRange = GetExprRange(S.Context, E, S.isConstantEvaluated()); + unsigned int SourcePrecision = SourceRange.Width; + + // Determine the number of precision bits in the + // target floating point type. + unsigned int TargetPrecision = llvm::APFloatBase::semanticsPrecision( + S.Context.getFloatTypeSemantics(QualType(TargetBT, 0))); + + if (SourcePrecision > 0 && TargetPrecision > 0 && + SourcePrecision > TargetPrecision) { + + llvm::APSInt SourceInt; + if (E->isIntegerConstantExpr(SourceInt, S.Context)) { + // If the source integer is a constant, convert it to the target + // floating point type. Issue a warning if the value changes + // during the whole conversion. + llvm::APFloat TargetFloatValue( + S.Context.getFloatTypeSemantics(QualType(TargetBT, 0))); + llvm::APFloat::opStatus ConversionStatus = + TargetFloatValue.convertFromAPInt( + SourceInt, SourceBT->isSignedInteger(), + llvm::APFloat::rmNearestTiesToEven); + + if (ConversionStatus != llvm::APFloat::opOK) { + std::string PrettySourceValue = SourceInt.toString(10); + SmallString<32> PrettyTargetValue; + TargetFloatValue.toString(PrettyTargetValue, TargetPrecision); + + S.DiagRuntimeBehavior( + E->getExprLoc(), E, + S.PDiag(diag::warn_impcast_integer_float_precision_constant) + << PrettySourceValue << PrettyTargetValue << E->getType() << T + << E->getSourceRange() << clang::SourceRange(CC)); + } + } else { + // Otherwise, the implicit conversion may lose precision. + DiagnoseImpCast(S, E, T, CC, + diag::warn_impcast_integer_float_precision); + } + } + } + DiagnoseNullConversion(S, E, T, CC); S.DiscardMisalignedMemberAddress(Target, E); + if (Target->isBooleanType()) + DiagnoseIntInBoolContext(S, E); + if (!Source->isIntegerType() || !Target->isIntegerType()) return; @@ -11412,6 +11736,14 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, if (Target->isSpecificBuiltinType(BuiltinType::Bool)) return; + if (isObjCSignedCharBool(S, T) && !Source->isCharType() && + !E->isKnownToHaveBooleanValue()) { + return adornObjCBoolConversionDiagWithTernaryFixit( + S, E, + S.Diag(CC, diag::warn_impcast_int_to_objc_signed_char_bool) + << E->getType()); + } + IntRange SourceRange = GetExprRange(S.Context, E, S.isConstantEvaluated()); IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target); @@ -11556,6 +11888,11 @@ 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); // If -Wconversion would have warned about either of the candidates // for a signedness conversion to the context type... @@ -11590,14 +11927,27 @@ static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { /// AnalyzeImplicitConversions - Find and report any interesting /// implicit conversions in the given expression. There are a couple /// of competing diagnostics here, -Wconversion and -Wsign-compare. -static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, - SourceLocation CC) { +static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC, + bool IsListInit/*= false*/) { QualType T = OrigE->getType(); Expr *E = OrigE->IgnoreParenImpCasts(); + // Propagate whether we are in a C++ list initialization expression. + // If so, we do not issue warnings for implicit int-float conversion + // precision loss, because C++11 narrowing already handles it. + IsListInit = + IsListInit || (isa<InitListExpr>(OrigE) && S.getLangOpts().CPlusPlus); + if (E->isTypeDependent() || E->isValueDependent()) return; + if (const auto *UO = dyn_cast<UnaryOperator>(E)) + if (UO->getOpcode() == UO_Not && + UO->getSubExpr()->isKnownToHaveBooleanValue()) + S.Diag(UO->getBeginLoc(), diag::warn_bitwise_negation_bool) + << OrigE->getSourceRange() << T->isBooleanType() + << FixItHint::CreateReplacement(UO->getBeginLoc(), "!"); + // For conditional operators, we analyze the arguments as if they // were being fed directly into the output. if (isa<ConditionalOperator>(E)) { @@ -11614,7 +11964,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, // The non-canonical typecheck is just an optimization; // CheckImplicitConversion will filter out dead implicit conversions. if (E->getType() != T) - CheckImplicitConversion(S, E, T, CC); + CheckImplicitConversion(S, E, T, CC, nullptr, IsListInit); // Now continue drilling into this expression. @@ -11624,7 +11974,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, // FIXME: Use a more uniform representation for this. for (auto *SE : POE->semantics()) if (auto *OVE = dyn_cast<OpaqueValueExpr>(SE)) - AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC); + AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC, IsListInit); } // Skip past explicit casts. @@ -11632,7 +11982,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, E = CE->getSubExpr()->IgnoreParenImpCasts(); if (!CE->getType()->isVoidType() && E->getType()->isAtomicType()) S.Diag(E->getBeginLoc(), diag::warn_atomic_implicit_seq_cst); - return AnalyzeImplicitConversions(S, E, CC); + return AnalyzeImplicitConversions(S, E, CC, IsListInit); } if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { @@ -11671,7 +12021,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, // Ignore checking string literals that are in logical and operators. // This is a common pattern for asserts. continue; - AnalyzeImplicitConversions(S, ChildExpr, CC); + AnalyzeImplicitConversions(S, ChildExpr, CC, IsListInit); } if (BO && BO->isLogicalOp()) { @@ -12907,7 +13257,7 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, if (ND) DiagRuntimeBehavior(ND->getBeginLoc(), BaseExpr, - PDiag(diag::note_array_index_out_of_bounds) + PDiag(diag::note_array_declared_here) << ND->getDeclName()); } @@ -14229,7 +14579,7 @@ void Sema::RefersToMemberWithReducedAlignment( QualType BaseType = ME->getBase()->getType(); if (ME->isArrow()) BaseType = BaseType->getPointeeType(); - RecordDecl *RD = BaseType->getAs<RecordType>()->getDecl(); + RecordDecl *RD = BaseType->castAs<RecordType>()->getDecl(); if (RD->isInvalidDecl()) return; diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index e4bbee86e350..f24c3b234ff2 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -1185,6 +1185,9 @@ static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate, const CXXMethodDecl &Incumbent, const Qualifiers &ObjectQuals, ExprValueKind ObjectKind) { + // Base/derived shadowing is handled elsewhere. + if (Candidate.getDeclContext() != Incumbent.getDeclContext()) + return OverloadCompare::BothViable; if (Candidate.isVariadic() != Incumbent.isVariadic() || Candidate.getNumParams() != Incumbent.getNumParams() || Candidate.getMinRequiredArguments() != diff --git a/lib/Sema/SemaConcept.cpp b/lib/Sema/SemaConcept.cpp new file mode 100644 index 000000000000..848ccf543445 --- /dev/null +++ b/lib/Sema/SemaConcept.cpp @@ -0,0 +1,125 @@ +//===-- SemaConcept.cpp - Semantic Analysis for Constraints and Concepts --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for C++ constraints and concepts. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/Sema.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/Sema/TemplateDeduction.h" +#include "clang/Sema/Template.h" +#include "clang/AST/ExprCXX.h" +using namespace clang; +using namespace sema; + +bool Sema::CheckConstraintExpression(Expr *ConstraintExpression) { + // C++2a [temp.constr.atomic]p1 + // ..E shall be a constant expression of type bool. + + ConstraintExpression = ConstraintExpression->IgnoreParenImpCasts(); + + if (auto *BinOp = dyn_cast<BinaryOperator>(ConstraintExpression)) { + if (BinOp->getOpcode() == BO_LAnd || BinOp->getOpcode() == BO_LOr) + return CheckConstraintExpression(BinOp->getLHS()) && + CheckConstraintExpression(BinOp->getRHS()); + } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpression)) + return CheckConstraintExpression(C->getSubExpr()); + + // An atomic constraint! + if (ConstraintExpression->isTypeDependent()) + return true; + + QualType Type = ConstraintExpression->getType(); + if (!Context.hasSameUnqualifiedType(Type, Context.BoolTy)) { + Diag(ConstraintExpression->getExprLoc(), + diag::err_non_bool_atomic_constraint) << Type + << ConstraintExpression->getSourceRange(); + return false; + } + return true; +} + +bool +Sema::CalculateConstraintSatisfaction(ConceptDecl *NamedConcept, + MultiLevelTemplateArgumentList &MLTAL, + Expr *ConstraintExpr, + bool &IsSatisfied) { + ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts(); + + if (auto *BO = dyn_cast<BinaryOperator>(ConstraintExpr)) { + if (BO->getOpcode() == BO_LAnd) { + if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(), + IsSatisfied)) + return true; + if (!IsSatisfied) + 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) + return false; + return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(), + IsSatisfied); + } + } + else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) + return CalculateConstraintSatisfaction(NamedConcept, MLTAL, C->getSubExpr(), + IsSatisfied); + + EnterExpressionEvaluationContext ConstantEvaluated( + *this, Sema::ExpressionEvaluationContext::ConstantEvaluated); + + // 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); + + E = SubstExpr(ConstraintExpr, MLTAL); + if (E.isInvalid() || Trap.hasErrorOccurred()) { + // C++2a [temp.constr.atomic]p1 + // ...If substitution results in an invalid type or expression, the + // constraint is not satisfied. + IsSatisfied = false; + return false; + } + } + + if (!CheckConstraintExpression(E.get())) + 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); + return true; + } + + IsSatisfied = EvalResult.Val.getInt().getBoolValue(); + + return false; +}
\ No newline at end of file diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp index f0347af6a1bb..fd2fd35921ce 100644 --- a/lib/Sema/SemaCoroutine.cpp +++ b/lib/Sema/SemaCoroutine.cpp @@ -83,7 +83,7 @@ static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD, // ref-qualifier or with the & ref-qualifier // -- "rvalue reference to cv X" for functions declared with the && // ref-qualifier - QualType T = MD->getThisType()->getAs<PointerType>()->getPointeeType(); + QualType T = MD->getThisType()->castAs<PointerType>()->getPointeeType(); T = FnType->getRefQualifier() == RQ_RValue ? S.Context.getRValueReferenceType(T) : S.Context.getLValueReferenceType(T, /*SpelledAsLValue*/ true); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index a6c52b7d4b2b..62ec83967bff 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -107,7 +107,7 @@ class TypeNameValidatorCCC final : public CorrectionCandidateCallback { } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<TypeNameValidatorCCC>(*this); + return std::make_unique<TypeNameValidatorCCC>(*this); } private: @@ -845,18 +845,18 @@ static ParsedType buildNestedType(Sema &S, CXXScopeSpec &SS, return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } -Sema::NameClassification -Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, - SourceLocation NameLoc, const Token &NextToken, - bool IsAddressOfOperand, CorrectionCandidateCallback *CCC) { +Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, + IdentifierInfo *&Name, + SourceLocation NameLoc, + const Token &NextToken, + CorrectionCandidateCallback *CCC) { DeclarationNameInfo NameInfo(Name, NameLoc); ObjCMethodDecl *CurMethod = getCurMethodDecl(); - if (NextToken.is(tok::coloncolon)) { - NestedNameSpecInfo IdInfo(Name, NameLoc, NextToken.getLocation()); - BuildCXXNestedNameSpecifier(S, IdInfo, false, SS, nullptr, false); - } else if (getLangOpts().CPlusPlus && SS.isSet() && - isCurrentClassName(*Name, S, &SS)) { + assert(NextToken.isNot(tok::coloncolon) && + "parse nested name specifiers before calling ClassifyName"); + if (getLangOpts().CPlusPlus && SS.isSet() && + isCurrentClassName(*Name, S, &SS)) { // Per [class.qual]p2, this names the constructors of SS, not the // injected-class-name. We don't have a classification for that. // There's not much point caching this result, since the parser @@ -880,9 +880,15 @@ Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, // FIXME: This lookup really, really needs to be folded in to the normal // unqualified lookup mechanism. if (!SS.isSet() && CurMethod && !isResultTypeOrTemplate(Result, NextToken)) { - ExprResult E = LookupInObjCMethod(Result, S, Name, true); - if (E.get() || E.isInvalid()) - return E; + DeclResult Ivar = LookupIvarInObjCMethod(Result, S, Name); + if (Ivar.isInvalid()) + return NameClassification::Error(); + if (Ivar.isUsable()) + return NameClassification::NonType(cast<NamedDecl>(Ivar.get())); + + // We defer builtin creation until after ivar lookup inside ObjC methods. + if (Result.empty()) + LookupBuiltin(Result); } bool SecondTry = false; @@ -897,7 +903,7 @@ Corrected: // In C++, this is an ADL-only call. // FIXME: Reference? if (getLangOpts().CPlusPlus) - return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true); + return NameClassification::UndeclaredNonType(); // C90 6.3.2.2: // If the expression that precedes the parenthesized argument list in a @@ -911,11 +917,8 @@ Corrected: // appeared. // // We also allow this in C99 as an extension. - if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S)) { - Result.addDecl(D); - Result.resolveKind(); - return BuildDeclarationNameExpr(SS, Result, /*ADL=*/false); - } + if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S)) + return NameClassification::NonType(D); } if (getLangOpts().CPlusPlus2a && !SS.isSet() && NextToken.is(tok::less)) { @@ -990,9 +993,12 @@ Corrected: // reference the ivar. // FIXME: This is a gross hack. if (ObjCIvarDecl *Ivar = Result.getAsSingle<ObjCIvarDecl>()) { - Result.clear(); - ExprResult E(LookupInObjCMethod(Result, S, Ivar->getIdentifier())); - return E; + DeclResult R = + LookupIvarInObjCMethod(Result, S, Ivar->getIdentifier()); + if (R.isInvalid()) + return NameClassification::Error(); + if (R.isUsable()) + return NameClassification::NonType(Ivar); } goto Corrected; @@ -1018,9 +1024,7 @@ Corrected: // perform some heroics to see if we actually have a // template-argument-list, which would indicate a missing 'template' // keyword here. - return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(), - NameInfo, IsAddressOfOperand, - /*TemplateArgs=*/nullptr); + return NameClassification::DependentNonType(); } case LookupResult::Found: @@ -1167,9 +1171,57 @@ Corrected: return ParsedType::make(T); } + // FIXME: This is context-dependent. We need to defer building the member + // expression until the classification is consumed. if (FirstDecl->isCXXClassMember()) - return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, - nullptr, S); + return NameClassification::ContextIndependentExpr( + BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, nullptr, + S)); + + // If we already know which single declaration is referenced, just annotate + // that declaration directly. + bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren)); + if (Result.isSingleResult() && !ADL) + return NameClassification::NonType(Result.getRepresentativeDecl()); + + // Build an UnresolvedLookupExpr. Note that this doesn't depend on the + // context in which we performed classification, so it's safe to do now. + return NameClassification::ContextIndependentExpr( + BuildDeclarationNameExpr(SS, Result, ADL)); +} + +ExprResult +Sema::ActOnNameClassifiedAsUndeclaredNonType(IdentifierInfo *Name, + SourceLocation NameLoc) { + assert(getLangOpts().CPlusPlus && "ADL-only call in C?"); + CXXScopeSpec SS; + LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); + return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true); +} + +ExprResult +Sema::ActOnNameClassifiedAsDependentNonType(const CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool IsAddressOfOperand) { + DeclarationNameInfo NameInfo(Name, NameLoc); + return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(), + NameInfo, IsAddressOfOperand, + /*TemplateArgs=*/nullptr); +} + +ExprResult Sema::ActOnNameClassifiedAsNonType(Scope *S, const CXXScopeSpec &SS, + NamedDecl *Found, + SourceLocation NameLoc, + const Token &NextToken) { + if (getCurMethodDecl() && SS.isEmpty()) + if (auto *Ivar = dyn_cast<ObjCIvarDecl>(Found->getUnderlyingDecl())) + return BuildIvarRefExpr(S, NameLoc, Ivar); + + // Reconstruct the lookup result. + LookupResult Result(*this, Found->getDeclName(), NameLoc, LookupOrdinaryName); + Result.addDecl(Found); + Result.resolveKind(); bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren)); return BuildDeclarationNameExpr(SS, Result, ADL); @@ -1984,10 +2036,27 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, ASTContext::GetBuiltinTypeError Error; QualType R = Context.GetBuiltinType(ID, Error); if (Error) { - if (ForRedeclaration) - Diag(Loc, diag::warn_implicit_decl_requires_sysheader) - << getHeaderName(Context.BuiltinInfo, ID, Error) + if (!ForRedeclaration) + return nullptr; + + // If we have a builtin without an associated type we should not emit a + // warning when we were not able to find a type for it. + if (Error == ASTContext::GE_Missing_type) + return nullptr; + + // If we could not find a type for setjmp it is because the jmp_buf type was + // not defined prior to the setjmp declaration. + if (Error == ASTContext::GE_Missing_setjmp) { + Diag(Loc, diag::warn_implicit_decl_no_jmp_buf) << Context.BuiltinInfo.getName(ID); + return nullptr; + } + + // Generally, we emit a warning that the declaration requires the + // appropriate header. + Diag(Loc, diag::warn_implicit_decl_requires_sysheader) + << getHeaderName(Context.BuiltinInfo, ID, Error) + << Context.BuiltinInfo.getName(ID); return nullptr; } @@ -2155,7 +2224,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, if (!T->isPointerType()) break; if (!T->isVoidPointerType()) { - QualType PT = T->getAs<PointerType>()->getPointeeType(); + QualType PT = T->castAs<PointerType>()->getPointeeType(); if (!PT->isStructureType()) break; } @@ -2457,43 +2526,33 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, // previous decl", for example if the attribute needs to be consistent // between redeclarations, you need to call a custom merge function here. InheritableAttr *NewAttr = nullptr; - unsigned AttrSpellingListIndex = Attr->getSpellingListIndex(); if (const auto *AA = dyn_cast<AvailabilityAttr>(Attr)) NewAttr = S.mergeAvailabilityAttr( - D, AA->getRange(), AA->getPlatform(), AA->isImplicit(), - AA->getIntroduced(), AA->getDeprecated(), AA->getObsoleted(), - AA->getUnavailable(), AA->getMessage(), AA->getStrict(), - AA->getReplacement(), AMK, AA->getPriority(), AttrSpellingListIndex); + D, *AA, AA->getPlatform(), AA->isImplicit(), AA->getIntroduced(), + AA->getDeprecated(), AA->getObsoleted(), AA->getUnavailable(), + AA->getMessage(), AA->getStrict(), AA->getReplacement(), AMK, + AA->getPriority()); else if (const auto *VA = dyn_cast<VisibilityAttr>(Attr)) - NewAttr = S.mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(), - AttrSpellingListIndex); + NewAttr = S.mergeVisibilityAttr(D, *VA, VA->getVisibility()); else if (const auto *VA = dyn_cast<TypeVisibilityAttr>(Attr)) - NewAttr = S.mergeTypeVisibilityAttr(D, VA->getRange(), VA->getVisibility(), - AttrSpellingListIndex); + NewAttr = S.mergeTypeVisibilityAttr(D, *VA, VA->getVisibility()); else if (const auto *ImportA = dyn_cast<DLLImportAttr>(Attr)) - NewAttr = S.mergeDLLImportAttr(D, ImportA->getRange(), - AttrSpellingListIndex); + NewAttr = S.mergeDLLImportAttr(D, *ImportA); else if (const auto *ExportA = dyn_cast<DLLExportAttr>(Attr)) - NewAttr = S.mergeDLLExportAttr(D, ExportA->getRange(), - AttrSpellingListIndex); + NewAttr = S.mergeDLLExportAttr(D, *ExportA); else if (const auto *FA = dyn_cast<FormatAttr>(Attr)) - NewAttr = S.mergeFormatAttr(D, FA->getRange(), FA->getType(), - FA->getFormatIdx(), FA->getFirstArg(), - AttrSpellingListIndex); + NewAttr = S.mergeFormatAttr(D, *FA, FA->getType(), FA->getFormatIdx(), + FA->getFirstArg()); else if (const auto *SA = dyn_cast<SectionAttr>(Attr)) - NewAttr = S.mergeSectionAttr(D, SA->getRange(), SA->getName(), - AttrSpellingListIndex); + NewAttr = S.mergeSectionAttr(D, *SA, SA->getName()); else if (const auto *CSA = dyn_cast<CodeSegAttr>(Attr)) - NewAttr = S.mergeCodeSegAttr(D, CSA->getRange(), CSA->getName(), - AttrSpellingListIndex); + NewAttr = S.mergeCodeSegAttr(D, *CSA, CSA->getName()); else if (const auto *IA = dyn_cast<MSInheritanceAttr>(Attr)) - NewAttr = S.mergeMSInheritanceAttr(D, IA->getRange(), IA->getBestCase(), - AttrSpellingListIndex, + NewAttr = S.mergeMSInheritanceAttr(D, *IA, IA->getBestCase(), IA->getSemanticSpelling()); else if (const auto *AA = dyn_cast<AlwaysInlineAttr>(Attr)) - NewAttr = S.mergeAlwaysInlineAttr(D, AA->getRange(), - &S.Context.Idents.get(AA->getSpelling()), - AttrSpellingListIndex); + NewAttr = S.mergeAlwaysInlineAttr(D, *AA, + &S.Context.Idents.get(AA->getSpelling())); else if (S.getLangOpts().CUDA && isa<FunctionDecl>(D) && (isa<CUDAHostAttr>(Attr) || isa<CUDADeviceAttr>(Attr) || isa<CUDAGlobalAttr>(Attr))) { @@ -2501,9 +2560,9 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, // overloading purposes and must not be merged. return false; } else if (const auto *MA = dyn_cast<MinSizeAttr>(Attr)) - NewAttr = S.mergeMinSizeAttr(D, MA->getRange(), AttrSpellingListIndex); + NewAttr = S.mergeMinSizeAttr(D, *MA); else if (const auto *OA = dyn_cast<OptimizeNoneAttr>(Attr)) - NewAttr = S.mergeOptimizeNoneAttr(D, OA->getRange(), AttrSpellingListIndex); + NewAttr = S.mergeOptimizeNoneAttr(D, *OA); else if (const auto *InternalLinkageA = dyn_cast<InternalLinkageAttr>(Attr)) NewAttr = S.mergeInternalLinkageAttr(D, *InternalLinkageA); else if (const auto *CommonA = dyn_cast<CommonAttr>(Attr)) @@ -2517,8 +2576,7 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, AMK == Sema::AMK_ProtocolImplementation)) NewAttr = nullptr; else if (const auto *UA = dyn_cast<UuidAttr>(Attr)) - NewAttr = S.mergeUuidAttr(D, UA->getRange(), AttrSpellingListIndex, - UA->getGuid()); + NewAttr = S.mergeUuidAttr(D, *UA, UA->getGuid()); else if (const auto *SLHA = dyn_cast<SpeculativeLoadHardeningAttr>(Attr)) NewAttr = S.mergeSpeculativeLoadHardeningAttr(D, *SLHA); else if (const auto *SLHA = dyn_cast<NoSpeculativeLoadHardeningAttr>(Attr)) @@ -2635,6 +2693,15 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { --E; continue; } + } else if (isa<SelectAnyAttr>(NewAttribute) && + cast<VarDecl>(New)->isInline() && + !cast<VarDecl>(New)->isInlineSpecified()) { + // Don't warn about applying selectany to implicitly inline variables. + // Older compilers and language modes would require the use of selectany + // to make such variables inline, and it would have no effect if we + // honored it. + ++I; + continue; } S.Diag(NewAttribute->getLocation(), @@ -2645,6 +2712,60 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { } } +static void diagnoseMissingConstinit(Sema &S, const VarDecl *InitDecl, + const ConstInitAttr *CIAttr, + bool AttrBeforeInit) { + SourceLocation InsertLoc = InitDecl->getInnerLocStart(); + + // Figure out a good way to write this specifier on the old declaration. + // FIXME: We should just use the spelling of CIAttr, but we don't preserve + // enough of the attribute list spelling information to extract that without + // heroics. + std::string SuitableSpelling; + if (S.getLangOpts().CPlusPlus2a) + SuitableSpelling = + S.PP.getLastMacroWithSpelling(InsertLoc, {tok::kw_constinit}); + if (SuitableSpelling.empty() && S.getLangOpts().CPlusPlus11) + SuitableSpelling = S.PP.getLastMacroWithSpelling( + InsertLoc, + {tok::l_square, tok::l_square, S.PP.getIdentifierInfo("clang"), + tok::coloncolon, + S.PP.getIdentifierInfo("require_constant_initialization"), + tok::r_square, tok::r_square}); + if (SuitableSpelling.empty()) + SuitableSpelling = S.PP.getLastMacroWithSpelling( + InsertLoc, + {tok::kw___attribute, tok::l_paren, tok::r_paren, + S.PP.getIdentifierInfo("require_constant_initialization"), + tok::r_paren, tok::r_paren}); + if (SuitableSpelling.empty() && S.getLangOpts().CPlusPlus2a) + SuitableSpelling = "constinit"; + if (SuitableSpelling.empty() && S.getLangOpts().CPlusPlus11) + SuitableSpelling = "[[clang::require_constant_initialization]]"; + if (SuitableSpelling.empty()) + SuitableSpelling = "__attribute__((require_constant_initialization))"; + SuitableSpelling += " "; + + if (AttrBeforeInit) { + // extern constinit int a; + // int a = 0; // error (missing 'constinit'), accepted as extension + assert(CIAttr->isConstinit() && "should not diagnose this for attribute"); + S.Diag(InitDecl->getLocation(), diag::ext_constinit_missing) + << InitDecl << FixItHint::CreateInsertion(InsertLoc, SuitableSpelling); + S.Diag(CIAttr->getLocation(), diag::note_constinit_specified_here); + } else { + // int a = 0; + // constinit extern int a; // error (missing 'constinit') + S.Diag(CIAttr->getLocation(), + CIAttr->isConstinit() ? diag::err_constinit_added_too_late + : diag::warn_require_const_init_added_too_late) + << FixItHint::CreateRemoval(SourceRange(CIAttr->getLocation())); + S.Diag(InitDecl->getLocation(), diag::note_constinit_missing_here) + << CIAttr->isConstinit() + << FixItHint::CreateInsertion(InsertLoc, SuitableSpelling); + } +} + /// mergeDeclAttributes - Copy attributes from the Old decl to the New one. void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old, AvailabilityMergeKind AMK) { @@ -2657,12 +2778,47 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old, if (!Old->hasAttrs() && !New->hasAttrs()) return; + // [dcl.constinit]p1: + // If the [constinit] specifier is applied to any declaration of a + // variable, it shall be applied to the initializing declaration. + const auto *OldConstInit = Old->getAttr<ConstInitAttr>(); + const auto *NewConstInit = New->getAttr<ConstInitAttr>(); + if (bool(OldConstInit) != bool(NewConstInit)) { + const auto *OldVD = cast<VarDecl>(Old); + auto *NewVD = cast<VarDecl>(New); + + // Find the initializing declaration. Note that we might not have linked + // the new declaration into the redeclaration chain yet. + const VarDecl *InitDecl = OldVD->getInitializingDeclaration(); + if (!InitDecl && + (NewVD->hasInit() || NewVD->isThisDeclarationADefinition())) + InitDecl = NewVD; + + if (InitDecl == NewVD) { + // This is the initializing declaration. If it would inherit 'constinit', + // that's ill-formed. (Note that we do not apply this to the attribute + // form). + if (OldConstInit && OldConstInit->isConstinit()) + diagnoseMissingConstinit(*this, NewVD, OldConstInit, + /*AttrBeforeInit=*/true); + } else if (NewConstInit) { + // This is the first time we've been told that this declaration should + // have a constant initializer. If we already saw the initializing + // declaration, this is too late. + if (InitDecl && InitDecl != NewVD) { + diagnoseMissingConstinit(*this, InitDecl, NewConstInit, + /*AttrBeforeInit=*/false); + NewVD->dropAttr<ConstInitAttr>(); + } + } + } + // Attributes declared post-definition are currently ignored. checkNewAttributesAfterDef(*this, New, Old); if (AsmLabelAttr *NewA = New->getAttr<AsmLabelAttr>()) { if (AsmLabelAttr *OldA = Old->getAttr<AsmLabelAttr>()) { - if (OldA->getLabel() != NewA->getLabel()) { + if (!OldA->isEquivalent(NewA)) { // This redeclaration changes __asm__ label. Diag(New->getLocation(), diag::err_different_asm_label); Diag(OldA->getLocation(), diag::note_previous_declaration); @@ -3458,7 +3614,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, } } - if (OldQTypeForComparison == NewQType) + // If the function types are compatible, merge the declarations. Ignore the + // exception specifier because it was already checked above in + // CheckEquivalentExceptionSpec, and we don't want follow-on diagnostics + // about incompatible types under -fms-compatibility. + if (Context.hasSameFunctionTypeIgnoringExceptionSpec(OldQTypeForComparison, + NewQType)) return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld); // If the types are imprecise (due to dependent constructs in friends or @@ -4090,11 +4251,11 @@ void Sema::notePreviousDefinition(const NamedDecl *Old, SourceLocation New) { // Is it the same file and same offset? Provide more information on why // this leads to a redefinition error. - bool EmittedDiag = false; if (FNew == FOld && FNewDecLoc.second == FOldDecLoc.second) { SourceLocation OldIncLoc = SrcMgr.getIncludeLoc(FOldDecLoc.first); SourceLocation NewIncLoc = SrcMgr.getIncludeLoc(FNewDecLoc.first); - EmittedDiag = noteFromModuleOrInclude(Old->getOwningModule(), OldIncLoc); + bool EmittedDiag = + noteFromModuleOrInclude(Old->getOwningModule(), OldIncLoc); EmittedDiag |= noteFromModuleOrInclude(getCurrentModule(), NewIncLoc); // If the header has no guards, emit a note suggesting one. @@ -4175,9 +4336,11 @@ void Sema::handleTagNumbering(const TagDecl *Tag, Scope *TagScope) { } // If this tag isn't a direct child of a class, number it if it is local. + MangleNumberingContext *MCtx; Decl *ManglingContextDecl; - if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext( - Tag->getDeclContext(), ManglingContextDecl)) { + std::tie(MCtx, ManglingContextDecl) = + getCurrentMangleNumberContext(Tag->getDeclContext()); + if (MCtx) { Context.setManglingNumber( Tag, MCtx->getManglingNumber( Tag, getMSManglingNumber(getLangOpts(), TagScope))); @@ -4299,13 +4462,13 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, // and definitions of functions and variables. // C++2a [dcl.constexpr]p1: The consteval specifier shall be applied only to // the declaration of a function or function template - bool IsConsteval = DS.getConstexprSpecifier() == CSK_consteval; if (Tag) Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag) - << GetDiagnosticTypeSpecifierID(DS.getTypeSpecType()) << IsConsteval; + << GetDiagnosticTypeSpecifierID(DS.getTypeSpecType()) + << DS.getConstexprSpecifier(); else Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_wrong_decl_kind) - << IsConsteval; + << DS.getConstexprSpecifier(); // Don't emit warnings after this error. return TagD; } @@ -4497,7 +4660,7 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, TypeSpecType == DeclSpec::TST_enum) { for (const ParsedAttr &AL : DS.getAttributes()) Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored) - << AL.getName() << GetDiagnosticTypeSpecifierID(TypeSpecType); + << AL << GetDiagnosticTypeSpecifierID(TypeSpecType); } } @@ -4686,12 +4849,12 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, bool Invalid = false; if (getLangOpts().CPlusPlus) { const char *PrevSpec = nullptr; - unsigned DiagID; if (Record->isUnion()) { // C++ [class.union]p6: // C++17 [class.union.anon]p2: // Anonymous unions declared in a named namespace or in the // global namespace shall be declared static. + unsigned DiagID; DeclContext *OwnerScope = Owner->getRedeclContext(); if (DS.getStorageClassSpec() != DeclSpec::SCS_static && (OwnerScope->isTranslationUnit() || @@ -4913,9 +5076,11 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, if (VarDecl *NewVD = dyn_cast<VarDecl>(Anon)) { if (getLangOpts().CPlusPlus && NewVD->isStaticLocal()) { + MangleNumberingContext *MCtx; Decl *ManglingContextDecl; - if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext( - NewVD->getDeclContext(), ManglingContextDecl)) { + std::tie(MCtx, ManglingContextDecl) = + getCurrentMangleNumberContext(NewVD->getDeclContext()); + if (MCtx) { Context.setManglingNumber( NewVD, MCtx->getManglingNumber( NewVD, getMSManglingNumber(getLangOpts(), S))); @@ -5649,8 +5814,8 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T, return QualType(); } - return Context.getConstantArrayType(VLATy->getElementType(), - Res, ArrayType::Normal, 0); + return Context.getConstantArrayType( + VLATy->getElementType(), Res, VLATy->getSizeExpr(), ArrayType::Normal, 0); } static void @@ -5760,7 +5925,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, << getLangOpts().CPlusPlus17; if (D.getDeclSpec().hasConstexprSpecifier()) Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) - << 1 << (D.getDeclSpec().getConstexprSpecifier() == CSK_consteval); + << 1 << D.getDeclSpec().getConstexprSpecifier(); if (D.getName().Kind != UnqualifiedIdKind::IK_Identifier) { if (D.getName().Kind == UnqualifiedIdKind::IK_DeductionGuideName) @@ -5842,6 +6007,8 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD, if (!Previous.empty()) { Redeclaration = true; MergeTypedefNameDecl(S, NewTD, Previous); + } else { + inferGslPointerAttribute(NewTD); } if (ShadowedDecl && !Redeclaration) @@ -6171,9 +6338,8 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, << NewDecl; S.Diag(OldDecl->getLocation(), diag::note_previous_declaration); NewDecl->dropAttr<DLLImportAttr>(); - NewDecl->addAttr(::new (S.Context) DLLExportAttr( - NewImportAttr->getRange(), S.Context, - NewImportAttr->getSpellingListIndex())); + NewDecl->addAttr( + DLLExportAttr::CreateImplicit(S.Context, NewImportAttr->getRange())); } else { S.Diag(NewDecl->getLocation(), diag::warn_redeclaration_without_attribute_prev_attribute_ignored) @@ -6658,19 +6824,6 @@ NamedDecl *Sema::ActOnVariableDeclarator( if (TemplateParamLists.size() > VDTemplateParamLists) NewVD->setTemplateParameterListsInfo( Context, TemplateParamLists.drop_back(VDTemplateParamLists)); - - if (D.getDeclSpec().hasConstexprSpecifier()) { - NewVD->setConstexpr(true); - // C++1z [dcl.spec.constexpr]p1: - // A static data member declared with the constexpr specifier is - // implicitly an inline variable. - if (NewVD->isStaticDataMember() && getLangOpts().CPlusPlus17) - NewVD->setImplicitlyInline(); - if (D.getDeclSpec().getConstexprSpecifier() == CSK_consteval) - Diag(D.getDeclSpec().getConstexprSpecLoc(), - diag::err_constexpr_wrong_decl_kind) - << /*consteval*/ 1; - } } if (D.getDeclSpec().isInlineSpecified()) { @@ -6736,6 +6889,38 @@ NamedDecl *Sema::ActOnVariableDeclarator( NewVD->setTSCSpec(TSCS); } + switch (D.getDeclSpec().getConstexprSpecifier()) { + case CSK_unspecified: + break; + + case CSK_consteval: + Diag(D.getDeclSpec().getConstexprSpecLoc(), + diag::err_constexpr_wrong_decl_kind) + << D.getDeclSpec().getConstexprSpecifier(); + LLVM_FALLTHROUGH; + + case CSK_constexpr: + NewVD->setConstexpr(true); + // C++1z [dcl.spec.constexpr]p1: + // A static data member declared with the constexpr specifier is + // implicitly an inline variable. + if (NewVD->isStaticDataMember() && + (getLangOpts().CPlusPlus17 || + Context.getTargetInfo().getCXXABI().isMicrosoft())) + NewVD->setImplicitlyInline(); + break; + + case CSK_constinit: + if (!NewVD->hasGlobalStorage()) + Diag(D.getDeclSpec().getConstexprSpecLoc(), + diag::err_constinit_local_variable); + else + NewVD->addAttr(ConstInitAttr::Create( + Context, D.getDeclSpec().getConstexprSpecLoc(), + AttributeCommonInfo::AS_Keyword, ConstInitAttr::Keyword_constinit)); + break; + } + // C99 6.7.4p3 // An inline definition of a function with external linkage shall // not contain a definition of a modifiable object with static or @@ -6786,7 +6971,7 @@ NamedDecl *Sema::ActOnVariableDeclarator( if (EmitTLSUnsupportedError && ((getLangOpts().CUDA && DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) || (getLangOpts().OpenMPIsDevice && - NewVD->hasAttr<OMPDeclareTargetDeclAttr>()))) + OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(NewVD)))) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_thread_unsupported); // CUDA B.2.5: "__shared__ and __constant__ variables have implied static @@ -6854,8 +7039,8 @@ NamedDecl *Sema::ActOnVariableDeclarator( } } - NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), - Context, Label, 0)); + NewVD->addAttr(::new (Context) AsmLabelAttr( + Context, SE->getStrTokenLoc(0), Label, /*IsLiteralLabel=*/true)); } else if (!ExtnameUndeclaredIdentifiers.empty()) { llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I = ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier()); @@ -6961,9 +7146,11 @@ NamedDecl *Sema::ActOnVariableDeclarator( RegisterLocallyScopedExternCDecl(NewVD, S); if (getLangOpts().CPlusPlus && NewVD->isStaticLocal()) { + MangleNumberingContext *MCtx; Decl *ManglingContextDecl; - if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext( - NewVD->getDeclContext(), ManglingContextDecl)) { + std::tie(MCtx, ManglingContextDecl) = + getCurrentMangleNumberContext(NewVD->getDeclContext()); + if (MCtx) { Context.setManglingNumber( NewVD, MCtx->getManglingNumber( NewVD, getMSManglingNumber(getLangOpts(), S))); @@ -7638,7 +7825,7 @@ struct FindOverriddenMethod { /// CXXRecordDecl::lookupInBases(). bool operator()(const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { RecordDecl *BaseRecord = - Specifier->getType()->getAs<RecordType>()->getDecl(); + Specifier->getType()->castAs<RecordType>()->getDecl(); DeclarationName Name = Method->getDeclName(); @@ -7772,7 +7959,7 @@ class DifferentNameValidatorCCC final : public CorrectionCandidateCallback { } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<DifferentNameValidatorCCC>(*this); + return std::make_unique<DifferentNameValidatorCCC>(*this); } private: @@ -7976,7 +8163,7 @@ static StorageClass getFunctionStorageClass(Sema &SemaRef, Declarator &D) { return SC_None; } -static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, +static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, DeclContext *DC, QualType &R, TypeSourceInfo *TInfo, StorageClass SC, @@ -8008,13 +8195,22 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, } ExplicitSpecifier ExplicitSpecifier = D.getDeclSpec().getExplicitSpecifier(); + ConstexprSpecKind ConstexprKind = D.getDeclSpec().getConstexprSpecifier(); + if (ConstexprKind == CSK_constinit) { + SemaRef.Diag(D.getDeclSpec().getConstexprSpecLoc(), + diag::err_constexpr_wrong_decl_kind) + << ConstexprKind; + ConstexprKind = CSK_unspecified; + D.getMutableDeclSpec().ClearConstexprSpec(); + } + // Check that the return type is not an abstract class type. // For record types, this is done by the AbstractClassUsageDiagnoser once // the class has been completely parsed. if (!DC->isRecord() && SemaRef.RequireNonAbstractType( - D.getIdentifierLoc(), R->getAs<FunctionType>()->getReturnType(), + D.getIdentifierLoc(), R->castAs<FunctionType>()->getReturnType(), diag::err_abstract_type_in_decl, SemaRef.AbstractReturnType)) D.setInvalidType(); @@ -8034,10 +8230,10 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, if (DC->isRecord()) { R = SemaRef.CheckDestructorDeclarator(D, R, SC); CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); - CXXDestructorDecl *NewDD = - CXXDestructorDecl::Create(SemaRef.Context, Record, D.getBeginLoc(), - NameInfo, R, TInfo, isInline, - /*isImplicitlyDeclared=*/false); + CXXDestructorDecl *NewDD = CXXDestructorDecl::Create( + SemaRef.Context, Record, D.getBeginLoc(), NameInfo, R, TInfo, + isInline, + /*isImplicitlyDeclared=*/false, ConstexprKind); // 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 @@ -8068,6 +8264,9 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, } SemaRef.CheckConversionDeclarator(D, R, SC); + if (D.isInvalidType()) + return nullptr; + IsVirtualOkay = true; return CXXConversionDecl::Create( SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R, @@ -8439,7 +8638,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, bool isInline = D.getDeclSpec().isInlineSpecified(); bool isVirtual = D.getDeclSpec().isVirtualSpecified(); bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier(); - ConstexprSpecKind ConstexprKind = D.getDeclSpec().getConstexprSpecifier(); isFriend = D.getDeclSpec().isFriendSpecified(); if (isFriend && !isInline && D.isFunctionDefinition()) { // C++ [class.friend]p5 @@ -8638,7 +8836,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - if (ConstexprKind != CSK_unspecified) { + if (ConstexprSpecKind ConstexprKind = + D.getDeclSpec().getConstexprSpecifier()) { // C++11 [dcl.constexpr]p2: constexpr functions and constexpr constructors // are implicitly inline. NewFD->setImplicitlyInline(); @@ -8646,9 +8845,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // C++11 [dcl.constexpr]p3: functions declared constexpr are required to // be either constructors or to return a literal type. Therefore, // destructors cannot be declared constexpr. - if (isa<CXXDestructorDecl>(NewFD)) + if (isa<CXXDestructorDecl>(NewFD) && !getLangOpts().CPlusPlus2a) { Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor) - << (ConstexprKind == CSK_consteval); + << ConstexprKind; + } } // If __module_private__ was specified, mark the function accordingly. @@ -8743,8 +8943,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(SE->getStrTokenLoc(0), Context, - SE->getString(), 0)); + NewFD->addAttr(::new (Context) + AsmLabelAttr(Context, SE->getStrTokenLoc(0), + SE->getString(), /*IsLiteralLabel=*/true)); } else if (!ExtnameUndeclaredIdentifiers.empty()) { llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I = ExtnameUndeclaredIdentifiers.find(NewFD->getIdentifier()); @@ -8842,9 +9043,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setParams(Params); if (D.getDeclSpec().isNoreturnSpecified()) - NewFD->addAttr( - ::new(Context) C11NoReturnAttr(D.getDeclSpec().getNoreturnSpecLoc(), - Context, 0)); + NewFD->addAttr(C11NoReturnAttr::Create(Context, + D.getDeclSpec().getNoreturnSpecLoc(), + AttributeCommonInfo::AS_Keyword)); // Functions returning a variably modified type violate C99 6.7.5.2p2 // because all functions have linkage. @@ -8856,19 +9057,18 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Apply an implicit SectionAttr if '#pragma clang section text' is active if (PragmaClangTextSection.Valid && D.isFunctionDefinition() && - !NewFD->hasAttr<SectionAttr>()) { - NewFD->addAttr(PragmaClangTextSectionAttr::CreateImplicit(Context, - PragmaClangTextSection.SectionName, - PragmaClangTextSection.PragmaLocation)); - } + !NewFD->hasAttr<SectionAttr>()) + NewFD->addAttr(PragmaClangTextSectionAttr::CreateImplicit( + Context, PragmaClangTextSection.SectionName, + PragmaClangTextSection.PragmaLocation, AttributeCommonInfo::AS_Pragma)); // Apply an implicit SectionAttr if #pragma code_seg is active. if (CodeSegStack.CurrentValue && D.isFunctionDefinition() && !NewFD->hasAttr<SectionAttr>()) { - NewFD->addAttr( - SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate, - CodeSegStack.CurrentValue->getString(), - CodeSegStack.CurrentPragmaLocation)); + NewFD->addAttr(SectionAttr::CreateImplicit( + Context, CodeSegStack.CurrentValue->getString(), + CodeSegStack.CurrentPragmaLocation, AttributeCommonInfo::AS_Pragma, + SectionAttr::Declspec_allocate)); if (UnifySection(CodeSegStack.CurrentValue->getString(), ASTContext::PSF_Implicit | ASTContext::PSF_Execute | ASTContext::PSF_Read, @@ -8999,7 +9199,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // may end up with different effective targets. Instead, a // specialization inherits its target attributes from its template // in the CheckFunctionTemplateSpecialization() call below. - if (getLangOpts().CUDA & !isFunctionTemplateSpecialization) + if (getLangOpts().CUDA && !isFunctionTemplateSpecialization) maybeAddCUDAHostDeviceAttrs(NewFD, Previous); // If it's a friend (and only if it's a friend), it's possible @@ -9404,12 +9604,11 @@ Attr *Sema::getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD, if (Attr *A = getImplicitCodeSegAttrFromClass(*this, FD)) return A; if (!FD->hasAttr<SectionAttr>() && IsDefinition && - CodeSegStack.CurrentValue) { - return SectionAttr::CreateImplicit(getASTContext(), - SectionAttr::Declspec_allocate, - CodeSegStack.CurrentValue->getString(), - CodeSegStack.CurrentPragmaLocation); - } + CodeSegStack.CurrentValue) + return SectionAttr::CreateImplicit( + getASTContext(), CodeSegStack.CurrentValue->getString(), + CodeSegStack.CurrentPragmaLocation, AttributeCommonInfo::AS_Pragma, + SectionAttr::Declspec_allocate); return nullptr; } @@ -9538,10 +9737,13 @@ static bool HasNonMultiVersionAttributes(const FunctionDecl *FD, return false; } -static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD, - const FunctionDecl *NewFD, - bool CausesMV, - MultiVersionKind MVType) { +bool Sema::areMultiversionVariantFunctionsCompatible( + const FunctionDecl *OldFD, const FunctionDecl *NewFD, + const PartialDiagnostic &NoProtoDiagID, + const PartialDiagnosticAt &NoteCausedDiagIDAt, + const PartialDiagnosticAt &NoSupportDiagIDAt, + const PartialDiagnosticAt &DiffDiagIDAt, bool TemplatesSupported, + bool ConstexprSupported, bool CLinkageMayDiffer) { enum DoesntSupport { FuncTemplates = 0, VirtFuncs = 1, @@ -9559,123 +9761,85 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD, ConstexprSpec = 2, InlineSpec = 3, StorageClass = 4, - Linkage = 5 + Linkage = 5, }; - bool IsCPUSpecificCPUDispatchMVType = - MVType == MultiVersionKind::CPUDispatch || - MVType == MultiVersionKind::CPUSpecific; - if (OldFD && !OldFD->getType()->getAs<FunctionProtoType>()) { - S.Diag(OldFD->getLocation(), diag::err_multiversion_noproto); - S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); + Diag(OldFD->getLocation(), NoProtoDiagID); + Diag(NoteCausedDiagIDAt.first, NoteCausedDiagIDAt.second); return true; } if (!NewFD->getType()->getAs<FunctionProtoType>()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_noproto); + return Diag(NewFD->getLocation(), NoProtoDiagID); - if (!S.getASTContext().getTargetInfo().supportsMultiVersioning()) { - S.Diag(NewFD->getLocation(), diag::err_multiversion_not_supported); - if (OldFD) - S.Diag(OldFD->getLocation(), diag::note_previous_declaration); - return true; - } - - // For now, disallow all other attributes. These should be opt-in, but - // an analysis of all of them is a future FIXME. - if (CausesMV && OldFD && HasNonMultiVersionAttributes(OldFD, MVType)) { - S.Diag(OldFD->getLocation(), diag::err_multiversion_no_other_attrs) - << IsCPUSpecificCPUDispatchMVType; - S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); - return true; - } - - if (HasNonMultiVersionAttributes(NewFD, MVType)) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_no_other_attrs) - << IsCPUSpecificCPUDispatchMVType; - - if (NewFD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) - << IsCPUSpecificCPUDispatchMVType << FuncTemplates; + if (!TemplatesSupported && + NewFD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) + return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second) + << FuncTemplates; if (const auto *NewCXXFD = dyn_cast<CXXMethodDecl>(NewFD)) { if (NewCXXFD->isVirtual()) - return S.Diag(NewCXXFD->getLocation(), - diag::err_multiversion_doesnt_support) - << IsCPUSpecificCPUDispatchMVType << VirtFuncs; + return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second) + << VirtFuncs; - if (const auto *NewCXXCtor = dyn_cast<CXXConstructorDecl>(NewFD)) - return S.Diag(NewCXXCtor->getLocation(), - diag::err_multiversion_doesnt_support) - << IsCPUSpecificCPUDispatchMVType << Constructors; + if (isa<CXXConstructorDecl>(NewCXXFD)) + return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second) + << Constructors; - if (const auto *NewCXXDtor = dyn_cast<CXXDestructorDecl>(NewFD)) - return S.Diag(NewCXXDtor->getLocation(), - diag::err_multiversion_doesnt_support) - << IsCPUSpecificCPUDispatchMVType << Destructors; + if (isa<CXXDestructorDecl>(NewCXXFD)) + return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second) + << Destructors; } if (NewFD->isDeleted()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) - << IsCPUSpecificCPUDispatchMVType << DeletedFuncs; + return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second) + << DeletedFuncs; if (NewFD->isDefaulted()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) - << IsCPUSpecificCPUDispatchMVType << DefaultedFuncs; + return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second) + << DefaultedFuncs; - if (NewFD->isConstexpr() && (MVType == MultiVersionKind::CPUDispatch || - MVType == MultiVersionKind::CPUSpecific)) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) - << IsCPUSpecificCPUDispatchMVType + if (!ConstexprSupported && NewFD->isConstexpr()) + return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second) << (NewFD->isConsteval() ? ConstevalFuncs : ConstexprFuncs); - QualType NewQType = S.getASTContext().getCanonicalType(NewFD->getType()); + QualType NewQType = Context.getCanonicalType(NewFD->getType()); const auto *NewType = cast<FunctionType>(NewQType); QualType NewReturnType = NewType->getReturnType(); if (NewReturnType->isUndeducedType()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) - << IsCPUSpecificCPUDispatchMVType << DeducedReturn; - - // Only allow transition to MultiVersion if it hasn't been used. - if (OldFD && CausesMV && OldFD->isUsed(false)) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_after_used); + return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second) + << DeducedReturn; // Ensure the return type is identical. if (OldFD) { - QualType OldQType = S.getASTContext().getCanonicalType(OldFD->getType()); + QualType OldQType = Context.getCanonicalType(OldFD->getType()); const auto *OldType = cast<FunctionType>(OldQType); FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); if (OldTypeInfo.getCC() != NewTypeInfo.getCC()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) - << CallingConv; + return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << CallingConv; QualType OldReturnType = OldType->getReturnType(); if (OldReturnType != NewReturnType) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) - << ReturnType; + return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << ReturnType; if (OldFD->getConstexprKind() != NewFD->getConstexprKind()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) - << ConstexprSpec; + return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << ConstexprSpec; if (OldFD->isInlineSpecified() != NewFD->isInlineSpecified()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) - << InlineSpec; + return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << InlineSpec; if (OldFD->getStorageClass() != NewFD->getStorageClass()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) - << StorageClass; + return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << StorageClass; - if (OldFD->isExternC() != NewFD->isExternC()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) - << Linkage; + if (!CLinkageMayDiffer && OldFD->isExternC() != NewFD->isExternC()) + return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << Linkage; - if (S.CheckEquivalentExceptionSpec( + if (CheckEquivalentExceptionSpec( OldFD->getType()->getAs<FunctionProtoType>(), OldFD->getLocation(), NewFD->getType()->getAs<FunctionProtoType>(), NewFD->getLocation())) return true; @@ -9683,6 +9847,52 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD, return false; } +static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD, + const FunctionDecl *NewFD, + bool CausesMV, + MultiVersionKind MVType) { + if (!S.getASTContext().getTargetInfo().supportsMultiVersioning()) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_not_supported); + if (OldFD) + S.Diag(OldFD->getLocation(), diag::note_previous_declaration); + return true; + } + + bool IsCPUSpecificCPUDispatchMVType = + MVType == MultiVersionKind::CPUDispatch || + MVType == MultiVersionKind::CPUSpecific; + + // For now, disallow all other attributes. These should be opt-in, but + // an analysis of all of them is a future FIXME. + if (CausesMV && OldFD && HasNonMultiVersionAttributes(OldFD, MVType)) { + S.Diag(OldFD->getLocation(), diag::err_multiversion_no_other_attrs) + << IsCPUSpecificCPUDispatchMVType; + S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); + return true; + } + + if (HasNonMultiVersionAttributes(NewFD, MVType)) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_no_other_attrs) + << IsCPUSpecificCPUDispatchMVType; + + // Only allow transition to MultiVersion if it hasn't been used. + if (OldFD && CausesMV && OldFD->isUsed(false)) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_after_used); + + return S.areMultiversionVariantFunctionsCompatible( + OldFD, NewFD, S.PDiag(diag::err_multiversion_noproto), + PartialDiagnosticAt(NewFD->getLocation(), + S.PDiag(diag::note_multiversioning_caused_here)), + PartialDiagnosticAt(NewFD->getLocation(), + S.PDiag(diag::err_multiversion_doesnt_support) + << IsCPUSpecificCPUDispatchMVType), + PartialDiagnosticAt(NewFD->getLocation(), + S.PDiag(diag::err_multiversion_diff)), + /*TemplatesSupported=*/false, + /*ConstexprSupported=*/!IsCPUSpecificCPUDispatchMVType, + /*CLinkageMayDiffer=*/false); +} + /// Check the validity of a multiversion function declaration that is the /// first of its kind. Also sets the multiversion'ness' of the function itself. /// @@ -10130,7 +10340,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD); if (!getLangOpts().CPlusPlus14 && MD && MD->isConstexpr() && !MD->isStatic() && !isa<CXXConstructorDecl>(MD) && - !MD->getMethodQualifiers().hasConst()) { + !isa<CXXDestructorDecl>(MD) && !MD->getMethodQualifiers().hasConst()) { CXXMethodDecl *OldMD = nullptr; if (OldDecl) OldMD = dyn_cast_or_null<CXXMethodDecl>(OldDecl->getAsFunction()); @@ -11120,6 +11330,15 @@ void Sema::checkNonTrivialCUnionInInitializer(const Expr *Init, namespace { +bool shouldIgnoreForRecordTriviality(const FieldDecl *FD) { + // Ignore unavailable fields. A field can be marked as unavailable explicitly + // in the source code or implicitly by the compiler if it is in a union + // defined in a system header and has non-trivial ObjC ownership + // qualifications. We don't want those fields to participate in determining + // whether the containing union is non-trivial. + return FD->hasAttr<UnavailableAttr>(); +} + struct DiagNonTrivalCUnionDefaultInitializeVisitor : DefaultInitializedTypeVisitor<DiagNonTrivalCUnionDefaultInitializeVisitor, void> { @@ -11173,7 +11392,8 @@ struct DiagNonTrivalCUnionDefaultInitializeVisitor << 0 << 0 << QT.getUnqualifiedType() << ""; for (const FieldDecl *FD : RD->fields()) - asDerived().visit(FD->getType(), FD, InNonTrivialUnion); + if (!shouldIgnoreForRecordTriviality(FD)) + asDerived().visit(FD->getType(), FD, InNonTrivialUnion); } void visitTrivial(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {} @@ -11237,7 +11457,8 @@ struct DiagNonTrivalCUnionDestructedTypeVisitor << 0 << 1 << QT.getUnqualifiedType() << ""; for (const FieldDecl *FD : RD->fields()) - asDerived().visit(FD->getType(), FD, InNonTrivialUnion); + if (!shouldIgnoreForRecordTriviality(FD)) + asDerived().visit(FD->getType(), FD, InNonTrivialUnion); } void visitTrivial(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {} @@ -11302,7 +11523,8 @@ struct DiagNonTrivalCUnionCopyVisitor << 0 << 2 << QT.getUnqualifiedType() << ""; for (const FieldDecl *FD : RD->fields()) - asDerived().visit(FD->getType(), FD, InNonTrivialUnion); + if (!shouldIgnoreForRecordTriviality(FD)) + asDerived().visit(FD->getType(), FD, InNonTrivialUnion); } void preVisit(QualType::PrimitiveCopyKind PCK, QualType QT, @@ -11527,9 +11749,12 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // Check for self-references within variable initializers. // Variables declared within a function/method body (except for references) // are handled by a dataflow analysis. - if (!VDecl->hasLocalStorage() || VDecl->getType()->isRecordType() || - VDecl->getType()->isReferenceType()) { - CheckSelfReference(*this, RealDecl, Init, DirectInit); + // This is undefined behavior in C++, but valid in C. + if (getLangOpts().CPlusPlus) { + if (!VDecl->hasLocalStorage() || VDecl->getType()->isRecordType() || + VDecl->getType()->isReferenceType()) { + CheckSelfReference(*this, RealDecl, Init, DirectInit); + } } // If the type changed, it means we had an incomplete type that was @@ -11853,7 +12078,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { if (Var->isStaticDataMember()) { // C++1z removes the relevant rule; the in-class declaration is always // a definition there. - if (!getLangOpts().CPlusPlus17) { + if (!getLangOpts().CPlusPlus17 && + !Context.getTargetInfo().getCXXABI().isMicrosoft()) { Diag(Var->getLocation(), diag::err_constexpr_static_mem_var_requires_init) << Var->getDeclName(); @@ -12239,11 +12465,11 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { Stack = &DataSegStack; SectionFlags |= ASTContext::PSF_Write; } - if (Stack->CurrentValue && !var->hasAttr<SectionAttr>()) { + if (Stack->CurrentValue && !var->hasAttr<SectionAttr>()) var->addAttr(SectionAttr::CreateImplicit( - Context, SectionAttr::Declspec_allocate, - Stack->CurrentValue->getString(), Stack->CurrentPragmaLocation)); - } + Context, Stack->CurrentValue->getString(), + Stack->CurrentPragmaLocation, AttributeCommonInfo::AS_Pragma, + SectionAttr::Declspec_allocate)); if (const SectionAttr *SA = var->getAttr<SectionAttr>()) if (UnifySection(SA->getName(), SectionFlags, var)) var->dropAttr<SectionAttr>(); @@ -12253,7 +12479,8 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { // attribute. if (CurInitSeg && var->getInit()) var->addAttr(InitSegAttr::CreateImplicit(Context, CurInitSeg->getString(), - CurInitSegLoc)); + CurInitSegLoc, + AttributeCommonInfo::AS_Pragma)); } // All the following checks are C++ only. @@ -12304,17 +12531,17 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { // Don't emit further diagnostics about constexpr globals since they // were just diagnosed. - if (!var->isConstexpr() && GlobalStorage && - var->hasAttr<RequireConstantInitAttr>()) { + if (!var->isConstexpr() && GlobalStorage && var->hasAttr<ConstInitAttr>()) { // FIXME: Need strict checking in C++03 here. bool DiagErr = getLangOpts().CPlusPlus11 ? !var->checkInitIsICE() : !checkConstInit(); if (DiagErr) { - auto attr = var->getAttr<RequireConstantInitAttr>(); + auto *Attr = var->getAttr<ConstInitAttr>(); Diag(var->getLocation(), diag::err_require_constant_init_failed) << Init->getSourceRange(); - Diag(attr->getLocation(), diag::note_declared_required_constant_init_here) - << attr->getRange(); + Diag(Attr->getLocation(), + diag::note_declared_required_constant_init_here) + << Attr->getRange() << Attr->isConstinit(); if (getLangOpts().CPlusPlus11) { APValue Value; SmallVector<PartialDiagnosticAt, 8> Notes; @@ -12386,9 +12613,7 @@ void Sema::CheckStaticLocalForDllExport(VarDecl *VD) { NewAttr->setInherited(true); VD->addAttr(NewAttr); } else if (Attr *A = FD->getAttr<DLLExportStaticLocalAttr>()) { - auto *NewAttr = ::new (getASTContext()) DLLExportAttr(A->getRange(), - getASTContext(), - A->getSpellingListIndex()); + auto *NewAttr = DLLExportAttr::CreateImplicit(getASTContext(), *A); NewAttr->setInherited(true); VD->addAttr(NewAttr); @@ -12398,9 +12623,7 @@ void Sema::CheckStaticLocalForDllExport(VarDecl *VD) { FD->addAttr(NewAttr); } else if (Attr *A = FD->getAttr<DLLImportStaticLocalAttr>()) { - auto *NewAttr = ::new (getASTContext()) DLLImportAttr(A->getRange(), - getASTContext(), - A->getSpellingListIndex()); + auto *NewAttr = DLLImportAttr::CreateImplicit(getASTContext(), *A); NewAttr->setInherited(true); VD->addAttr(NewAttr); } @@ -12420,17 +12643,25 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) { if (VD->hasGlobalStorage() && VD->isThisDeclarationADefinition() && !inTemplateInstantiation() && !VD->hasAttr<SectionAttr>()) { if (PragmaClangBSSSection.Valid) - VD->addAttr(PragmaClangBSSSectionAttr::CreateImplicit(Context, - PragmaClangBSSSection.SectionName, - PragmaClangBSSSection.PragmaLocation)); + VD->addAttr(PragmaClangBSSSectionAttr::CreateImplicit( + Context, PragmaClangBSSSection.SectionName, + PragmaClangBSSSection.PragmaLocation, + AttributeCommonInfo::AS_Pragma)); if (PragmaClangDataSection.Valid) - VD->addAttr(PragmaClangDataSectionAttr::CreateImplicit(Context, - PragmaClangDataSection.SectionName, - PragmaClangDataSection.PragmaLocation)); + VD->addAttr(PragmaClangDataSectionAttr::CreateImplicit( + Context, PragmaClangDataSection.SectionName, + PragmaClangDataSection.PragmaLocation, + AttributeCommonInfo::AS_Pragma)); if (PragmaClangRodataSection.Valid) - VD->addAttr(PragmaClangRodataSectionAttr::CreateImplicit(Context, - PragmaClangRodataSection.SectionName, - PragmaClangRodataSection.PragmaLocation)); + VD->addAttr(PragmaClangRodataSectionAttr::CreateImplicit( + Context, PragmaClangRodataSection.SectionName, + PragmaClangRodataSection.PragmaLocation, + AttributeCommonInfo::AS_Pragma)); + if (PragmaClangRelroSection.Valid) + VD->addAttr(PragmaClangRelroSectionAttr::CreateImplicit( + Context, PragmaClangRelroSection.SectionName, + PragmaClangRelroSection.PragmaLocation, + AttributeCommonInfo::AS_Pragma)); } if (auto *DD = dyn_cast<DecompositionDecl>(ThisDecl)) { @@ -12726,20 +12957,10 @@ void Sema::ActOnDocumentableDecls(ArrayRef<Decl *> Group) { } } - // See if there are any new comments that are not attached to a decl. - ArrayRef<RawComment *> Comments = Context.getRawCommentList().getComments(); - if (!Comments.empty() && - !Comments.back()->isAttached()) { - // There is at least one comment that not attached to a decl. - // Maybe it should be attached to one of these decls? - // - // Note that this way we pick up not only comments that precede the - // declaration, but also comments that *follow* the declaration -- thanks to - // the lookahead in the lexer: we've consumed the semicolon and looked - // ahead through comments. - for (unsigned i = 0, e = Group.size(); i != e; ++i) - Context.getCommentForDecl(Group[i], &PP); - } + // FIMXE: We assume every Decl in the group is in the same file. + // This is false when preprocessor constructs the group from decls in + // different files (e. g. macros or #include). + Context.attachCommentsToJustParsedDecls(Group, &getPreprocessor()); } /// Common checks for a parameter-declaration that should apply to both function @@ -12817,7 +13038,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { << getLangOpts().CPlusPlus17; if (DS.hasConstexprSpecifier()) Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr) - << 0 << (D.getDeclSpec().getConstexprSpecifier() == CSK_consteval); + << 0 << D.getDeclSpec().getConstexprSpecifier(); DiagnoseFunctionSpecifiers(DS); @@ -12977,6 +13198,13 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, Context.getAdjustedParameterType(T), TSInfo, SC, nullptr); + // Make a note if we created a new pack in the scope of a lambda, so that + // we know that references to that pack must also be expanded within the + // lambda scope. + if (New->isParameterPack()) + if (auto *LSI = getEnclosingLambda()) + LSI->LocalPacks.push_back(New); + if (New->getType().hasNonTrivialToPrimitiveDestructCUnion() || New->getType().hasNonTrivialToPrimitiveCopyCUnion()) checkNonTrivialCUnion(New->getType(), New->getLocation(), @@ -13817,8 +14045,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, } if (!IsInstantiation && FD && FD->isConstexpr() && !FD->isInvalidDecl() && - (!CheckConstexprFunctionDecl(FD) || - !CheckConstexprFunctionBody(FD, Body))) + !CheckConstexprFunctionDefinition(FD, CheckConstexprKind::Diagnose)) FD->setInvalidDecl(); if (FD && FD->hasAttr<NakedAttr>()) { @@ -14577,7 +14804,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, UPPC_FixedUnderlyingType)) EnumUnderlying = Context.IntTy.getTypePtr(); - } else if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { + } else if (Context.getTargetInfo().getTriple().isWindowsMSVCEnvironment()) { // For MSVC ABI compatibility, unfixed enums must use an underlying type // of 'int'. However, if this is an unfixed forward declaration, don't set // the underlying type unless the user enables -fms-compatibility. This @@ -15400,6 +15627,9 @@ CreateNewDecl: if (PrevDecl) mergeDeclAttributes(New, PrevDecl); + if (auto *CXXRD = dyn_cast<CXXRecordDecl>(New)) + inferGslOwnerPointerAttribute(CXXRD); + // If there's a #pragma GCC visibility in scope, set the visibility of this // record. AddPushedVisibilityAttribute(New); @@ -15469,8 +15699,9 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, return; if (FinalLoc.isValid()) - Record->addAttr(new (Context) - FinalAttr(FinalLoc, Context, IsFinalSpelledSealed)); + Record->addAttr(FinalAttr::Create( + Context, FinalLoc, AttributeCommonInfo::AS_Keyword, + static_cast<FinalAttr::Spelling>(IsFinalSpelledSealed))); // C++ [class]p2: // [...] The class-name is also inserted into the scope of the @@ -16372,6 +16603,21 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, << FixItHint::CreateInsertion(FD->getLocation(), "*"); QualType T = Context.getObjCObjectPointerType(FD->getType()); FD->setType(T); + } else if (Record && Record->isUnion() && + FD->getType().hasNonTrivialObjCLifetime() && + getSourceManager().isInSystemHeader(FD->getLocation()) && + !getLangOpts().CPlusPlus && !FD->hasAttr<UnavailableAttr>() && + (FD->getType().getObjCLifetime() != Qualifiers::OCL_Strong || + !Context.hasDirectOwnershipQualifier(FD->getType()))) { + // For backward compatibility, fields of C unions declared in system + // headers that have non-trivial ObjC ownership qualifications are marked + // as unavailable unless the qualifier is explicit and __strong. This can + // break ABI compatibility between programs compiled with ARC and MRR, but + // is a better option than rejecting programs using those unions under + // ARC. + FD->addAttr(UnavailableAttr::CreateImplicit( + Context, "", UnavailableAttr::IR_ARCFieldWithOwnership, + FD->getLocation())); } else if (getLangOpts().ObjC && getLangOpts().getGC() != LangOptions::NonGC && Record && !Record->hasObjectMember()) { @@ -16381,7 +16627,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, else if (Context.getAsArrayType(FD->getType())) { QualType BaseType = Context.getBaseElementType(FD->getType()); if (BaseType->isRecordType() && - BaseType->getAs<RecordType>()->getDecl()->hasObjectMember()) + BaseType->castAs<RecordType>()->getDecl()->hasObjectMember()) Record->setHasObjectMember(true); else if (BaseType->isObjCObjectPointerType() || BaseType.isObjCGCStrong()) @@ -16389,7 +16635,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, } } - if (Record && !getLangOpts().CPlusPlus && !FD->hasAttr<UnavailableAttr>()) { + if (Record && !getLangOpts().CPlusPlus && + !shouldIgnoreForRecordTriviality(FD)) { QualType FT = FD->getType(); if (FT.isNonTrivialToPrimitiveDefaultInitialize()) { Record->setNonTrivialToPrimitiveDefaultInitialize(true); @@ -16685,8 +16932,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, if (Enum->isDependentType() || Val->isTypeDependent()) EltTy = Context.DependentTy; else { - if (getLangOpts().CPlusPlus11 && Enum->isFixed() && - !getLangOpts().MSVCCompat) { + if (getLangOpts().CPlusPlus11 && Enum->isFixed()) { // C++11 [dcl.enum]p5: If the underlying type is fixed, [...] the // constant-expression in the enumerator-definition shall be a converted // constant expression of the underlying type. @@ -16711,15 +16957,19 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // we perform a non-narrowing conversion as part of converted constant // expression checking. if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) { - if (getLangOpts().MSVCCompat) { + if (Context.getTargetInfo() + .getTriple() + .isWindowsMSVCEnvironment()) { Diag(IdLoc, diag::ext_enumerator_too_large) << EltTy; - Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).get(); - } else + } else { Diag(IdLoc, diag::err_enumerator_too_large) << EltTy; - } else - Val = ImpCastExprToType(Val, EltTy, - EltTy->isBooleanType() ? - CK_IntegralToBoolean : CK_IntegralCast) + } + } + + // Cast to the underlying type. + Val = ImpCastExprToType(Val, EltTy, + EltTy->isBooleanType() ? CK_IntegralToBoolean + : CK_IntegralCast) .get(); } else if (getLangOpts().CPlusPlus) { // C++11 [dcl.enum]p5: @@ -17047,7 +17297,7 @@ static void CheckForDuplicateEnumValues(Sema &S, ArrayRef<Decl *> Elements, continue; // Create new vector and push values onto it. - auto Vec = llvm::make_unique<ECDVector>(); + auto Vec = std::make_unique<ECDVector>(); Vec->push_back(D); Vec->push_back(ECD); @@ -17371,8 +17621,10 @@ void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name, SourceLocation AliasNameLoc) { NamedDecl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName); - AsmLabelAttr *Attr = - AsmLabelAttr::CreateImplicit(Context, AliasName->getName(), AliasNameLoc); + AttributeCommonInfo Info(AliasName, SourceRange(AliasNameLoc), + AttributeCommonInfo::AS_Pragma); + AsmLabelAttr *Attr = AsmLabelAttr::CreateImplicit( + Context, AliasName->getName(), /*LiteralLabel=*/true, Info); // If a declaration that: // 1) declares a function or a variable @@ -17395,7 +17647,7 @@ void Sema::ActOnPragmaWeakID(IdentifierInfo* Name, Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName); if (PrevDecl) { - PrevDecl->addAttr(WeakAttr::CreateImplicit(Context, PragmaLoc)); + PrevDecl->addAttr(WeakAttr::CreateImplicit(Context, PragmaLoc, AttributeCommonInfo::AS_Pragma)); } else { (void)WeakUndeclaredIdentifiers.insert( std::pair<IdentifierInfo*,WeakInfo> @@ -17425,3 +17677,87 @@ void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name, Decl *Sema::getObjCDeclContext() const { return (dyn_cast_or_null<ObjCContainerDecl>(CurContext)); } + +Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD) { + // Templates are emitted when they're instantiated. + if (FD->isDependentContext()) + return FunctionEmissionStatus::TemplateDiscarded; + + FunctionEmissionStatus OMPES = FunctionEmissionStatus::Unknown; + if (LangOpts.OpenMPIsDevice) { + Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl()); + if (DevTy.hasValue()) { + if (*DevTy == OMPDeclareTargetDeclAttr::DT_Host) + OMPES = FunctionEmissionStatus::OMPDiscarded; + else if (DeviceKnownEmittedFns.count(FD) > 0) + OMPES = FunctionEmissionStatus::Emitted; + } + } else if (LangOpts.OpenMP) { + // In OpenMP 4.5 all the functions are host functions. + if (LangOpts.OpenMP <= 45) { + OMPES = FunctionEmissionStatus::Emitted; + } else { + Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl()); + // In OpenMP 5.0 or above, DevTy may be changed later by + // #pragma omp declare target to(*) device_type(*). Therefore DevTy + // having no value does not imply host. The emission status will be + // checked again at the end of compilation unit. + if (DevTy.hasValue()) { + if (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) { + OMPES = FunctionEmissionStatus::OMPDiscarded; + } else if (DeviceKnownEmittedFns.count(FD) > 0) { + OMPES = FunctionEmissionStatus::Emitted; + } + } + } + } + if (OMPES == FunctionEmissionStatus::OMPDiscarded || + (OMPES == FunctionEmissionStatus::Emitted && !LangOpts.CUDA)) + return OMPES; + + if (LangOpts.CUDA) { + // When compiling for device, host functions are never emitted. Similarly, + // when compiling for host, device and global functions are never emitted. + // (Technically, we do emit a host-side stub for global functions, but this + // doesn't count for our purposes here.) + Sema::CUDAFunctionTarget T = IdentifyCUDATarget(FD); + if (LangOpts.CUDAIsDevice && T == Sema::CFT_Host) + return FunctionEmissionStatus::CUDADiscarded; + if (!LangOpts.CUDAIsDevice && + (T == Sema::CFT_Device || T == Sema::CFT_Global)) + return FunctionEmissionStatus::CUDADiscarded; + + // Check whether this function is externally visible -- if so, it's + // known-emitted. + // + // We have to check the GVA linkage of the function's *definition* -- if we + // only have a declaration, we don't know whether or not the function will + // be emitted, because (say) the definition could include "inline". + FunctionDecl *Def = FD->getDefinition(); + + if (Def && + !isDiscardableGVALinkage(getASTContext().GetGVALinkageForFunction(Def)) + && (!LangOpts.OpenMP || OMPES == FunctionEmissionStatus::Emitted)) + return FunctionEmissionStatus::Emitted; + } + + // Otherwise, the function is known-emitted if it's in our set of + // known-emitted functions. + return (DeviceKnownEmittedFns.count(FD) > 0) + ? FunctionEmissionStatus::Emitted + : FunctionEmissionStatus::Unknown; +} + +bool Sema::shouldIgnoreInHostDeviceCheck(FunctionDecl *Callee) { + // Host-side references to a __global__ function refer to the stub, so the + // function itself is never emitted and therefore should not be marked. + // If we have host fn calls kernel fn calls host+device, the HD function + // does not get instantiated on the host. We model this by omitting at the + // call to the kernel from the callgraph. This ensures that, when compiling + // for host, only HD functions actually called from the host get marked as + // known-emitted. + return LangOpts.CUDA && !LangOpts.CUDAIsDevice && + IdentifyCUDATarget(Callee) == CFT_Global; +} diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index ee06f8ae5114..b2be6245a814 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -398,18 +398,11 @@ bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum, /// Applies the given attribute to the Decl without performing any /// additional semantic checking. template <typename AttrType> -static void handleSimpleAttribute(Sema &S, Decl *D, SourceRange SR, - unsigned SpellingIndex) { - D->addAttr(::new (S.Context) AttrType(SR, S.Context, SpellingIndex)); +static void handleSimpleAttribute(Sema &S, Decl *D, + const AttributeCommonInfo &CI) { + D->addAttr(::new (S.Context) AttrType(S.Context, CI)); } -template <typename AttrType> -static void handleSimpleAttribute(Sema &S, Decl *D, const ParsedAttr &AL) { - handleSimpleAttribute<AttrType>(S, D, AL.getRange(), - AL.getAttributeSpellingListIndex()); -} - - template <typename... DiagnosticArgs> static const Sema::SemaDiagnosticBuilder& appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr) { @@ -429,28 +422,16 @@ appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr, T &&ExtraArg, /// Otherwise, emit diagnostic {@code DiagID}, passing in all parameters /// specified in {@code ExtraArgs}. template <typename AttrType, typename... DiagnosticArgs> -static void -handleSimpleAttributeOrDiagnose(Sema &S, Decl *D, SourceRange SR, - unsigned SpellingIndex, - bool PassesCheck, - unsigned DiagID, DiagnosticArgs&&... ExtraArgs) { +static void handleSimpleAttributeOrDiagnose(Sema &S, Decl *D, + const AttributeCommonInfo &CI, + bool PassesCheck, unsigned DiagID, + DiagnosticArgs &&... ExtraArgs) { if (!PassesCheck) { Sema::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID); appendDiagnostics(DB, std::forward<DiagnosticArgs>(ExtraArgs)...); return; } - handleSimpleAttribute<AttrType>(S, D, SR, SpellingIndex); -} - -template <typename AttrType, typename... DiagnosticArgs> -static void -handleSimpleAttributeOrDiagnose(Sema &S, Decl *D, const ParsedAttr &AL, - bool PassesCheck, - unsigned DiagID, - DiagnosticArgs&&... ExtraArgs) { - return handleSimpleAttributeOrDiagnose<AttrType>( - S, D, AL.getRange(), AL.getAttributeSpellingListIndex(), PassesCheck, - DiagID, std::forward<DiagnosticArgs>(ExtraArgs)...); + handleSimpleAttribute<AttrType>(S, D, CI); } template <typename AttrType> @@ -566,7 +547,7 @@ static bool checkRecordDeclForAttr(const RecordDecl *RD) { // If it's type-dependent, we assume it could have the attribute. if (Ty.isDependentType()) return true; - return Ty.getAs<RecordType>()->getDecl()->hasAttr<AttrType>(); + return Ty.castAs<RecordType>()->getDecl()->hasAttr<AttrType>(); }, BPaths, true)) return true; @@ -745,9 +726,7 @@ static void handlePtGuardedVarAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!threadSafetyCheckIsPointer(S, D, AL)) return; - D->addAttr(::new (S.Context) - PtGuardedVarAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) PtGuardedVarAttr(S.Context, AL)); } static bool checkGuardedByAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, @@ -769,8 +748,7 @@ static void handleGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!checkGuardedByAttrCommon(S, D, AL, Arg)) return; - D->addAttr(::new (S.Context) GuardedByAttr( - AL.getRange(), S.Context, Arg, AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) GuardedByAttr(S.Context, AL, Arg)); } static void handlePtGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -781,8 +759,7 @@ static void handlePtGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!threadSafetyCheckIsPointer(S, D, AL)) return; - D->addAttr(::new (S.Context) PtGuardedByAttr( - AL.getRange(), S.Context, Arg, AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) PtGuardedByAttr(S.Context, AL, Arg)); } static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, @@ -811,9 +788,8 @@ static void handleAcquiredAfterAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; Expr **StartArg = &Args[0]; - D->addAttr(::new (S.Context) AcquiredAfterAttr( - AL.getRange(), S.Context, StartArg, Args.size(), - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + AcquiredAfterAttr(S.Context, AL, StartArg, Args.size())); } static void handleAcquiredBeforeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -822,9 +798,8 @@ static void handleAcquiredBeforeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; Expr **StartArg = &Args[0]; - D->addAttr(::new (S.Context) AcquiredBeforeAttr( - AL.getRange(), S.Context, StartArg, Args.size(), - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + AcquiredBeforeAttr(S.Context, AL, StartArg, Args.size())); } static bool checkLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, @@ -844,8 +819,7 @@ static void handleAssertSharedLockAttr(Sema &S, Decl *D, const ParsedAttr &AL) { unsigned Size = Args.size(); Expr **StartArg = Size == 0 ? nullptr : &Args[0]; D->addAttr(::new (S.Context) - AssertSharedLockAttr(AL.getRange(), S.Context, StartArg, Size, - AL.getAttributeSpellingListIndex())); + AssertSharedLockAttr(S.Context, AL, StartArg, Size)); } static void handleAssertExclusiveLockAttr(Sema &S, Decl *D, @@ -856,9 +830,8 @@ static void handleAssertExclusiveLockAttr(Sema &S, Decl *D, unsigned Size = Args.size(); Expr **StartArg = Size == 0 ? nullptr : &Args[0]; - D->addAttr(::new (S.Context) AssertExclusiveLockAttr( - AL.getRange(), S.Context, StartArg, Size, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + AssertExclusiveLockAttr(S.Context, AL, StartArg, Size)); } /// Checks to be sure that the given parameter number is in bounds, and @@ -919,8 +892,7 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } D->addAttr(::new (S.Context) - AllocSizeAttr(AL.getRange(), S.Context, SizeArgNo, NumberArgNo, - AL.getAttributeSpellingListIndex())); + AllocSizeAttr(S.Context, AL, SizeArgNo, NumberArgNo)); } static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, @@ -947,8 +919,7 @@ static void handleSharedTrylockFunctionAttr(Sema &S, Decl *D, return; D->addAttr(::new (S.Context) SharedTrylockFunctionAttr( - AL.getRange(), S.Context, AL.getArgAsExpr(0), Args.data(), Args.size(), - AL.getAttributeSpellingListIndex())); + S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size())); } static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D, @@ -958,8 +929,7 @@ static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D, return; D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr( - AL.getRange(), S.Context, AL.getArgAsExpr(0), Args.data(), - Args.size(), AL.getAttributeSpellingListIndex())); + S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size())); } static void handleLockReturnedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -970,9 +940,7 @@ static void handleLockReturnedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (Size == 0) return; - D->addAttr(::new (S.Context) - LockReturnedAttr(AL.getRange(), S.Context, Args[0], - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) LockReturnedAttr(S.Context, AL, Args[0])); } static void handleLocksExcludedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -988,8 +956,7 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { Expr **StartArg = &Args[0]; D->addAttr(::new (S.Context) - LocksExcludedAttr(AL.getRange(), S.Context, StartArg, Size, - AL.getAttributeSpellingListIndex())); + LocksExcludedAttr(S.Context, AL, StartArg, Size)); } static bool checkFunctionConditionAttr(Sema &S, Decl *D, const ParsedAttr &AL, @@ -1026,9 +993,7 @@ static void handleEnableIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) { Expr *Cond; StringRef Msg; if (checkFunctionConditionAttr(S, D, AL, Cond, Msg)) - D->addAttr(::new (S.Context) - EnableIfAttr(AL.getRange(), S.Context, Cond, Msg, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) EnableIfAttr(S.Context, AL, Cond, Msg)); } namespace { @@ -1100,8 +1065,7 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (const auto *FD = dyn_cast<FunctionDecl>(D)) ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond); D->addAttr(::new (S.Context) DiagnoseIfAttr( - AL.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, - cast<NamedDecl>(D), AL.getAttributeSpellingListIndex())); + S.Context, AL, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D))); } static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -1133,8 +1097,7 @@ static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) PassObjectSizeAttr( - AL.getRange(), S.Context, (int)Type, AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) PassObjectSizeAttr(S.Context, AL, (int)Type)); } static void handleConsumableAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -1154,9 +1117,7 @@ static void handleConsumableAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) - ConsumableAttr(AL.getRange(), S.Context, DefaultState, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ConsumableAttr(S.Context, AL, DefaultState)); } static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD, @@ -1207,8 +1168,7 @@ static void handleCallableWhenAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } D->addAttr(::new (S.Context) - CallableWhenAttr(AL.getRange(), S.Context, States.data(), - States.size(), AL.getAttributeSpellingListIndex())); + CallableWhenAttr(S.Context, AL, States.data(), States.size())); } static void handleParamTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -1242,9 +1202,7 @@ static void handleParamTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // return; //} - D->addAttr(::new (S.Context) - ParamTypestateAttr(AL.getRange(), S.Context, ParamState, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ParamTypestateAttr(S.Context, AL, ParamState)); } static void handleReturnTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -1289,9 +1247,7 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // return; //} - D->addAttr(::new (S.Context) - ReturnTypestateAttr(AL.getRange(), S.Context, ReturnState, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ReturnTypestateAttr(S.Context, AL, ReturnState)); } static void handleSetTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -1313,9 +1269,7 @@ static void handleSetTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) - SetTypestateAttr(AL.getRange(), S.Context, NewState, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) SetTypestateAttr(S.Context, AL, NewState)); } static void handleTestTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -1337,9 +1291,7 @@ static void handleTestTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) - TestTypestateAttr(AL.getRange(), S.Context, TestState, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) TestTypestateAttr(S.Context, AL, TestState)); } static void handleExtVectorTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -1349,8 +1301,7 @@ static void handleExtVectorTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handlePackedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (auto *TD = dyn_cast<TagDecl>(D)) - TD->addAttr(::new (S.Context) PackedAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + TD->addAttr(::new (S.Context) PackedAttr(S.Context, AL)); else if (auto *FD = dyn_cast<FieldDecl>(D)) { bool BitfieldByteAligned = (!FD->getType()->isDependentType() && !FD->getType()->isIncompleteType() && @@ -1363,15 +1314,13 @@ static void handlePackedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.Diag(AL.getLoc(), diag::warn_attribute_ignored_for_field_of_type) << AL << FD->getType(); else - FD->addAttr(::new (S.Context) PackedAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + FD->addAttr(::new (S.Context) PackedAttr(S.Context, AL)); } else { // Report warning about changed offset in the newer compiler versions. if (BitfieldByteAligned) S.Diag(AL.getLoc(), diag::warn_attribute_packed_for_bitfield); - FD->addAttr(::new (S.Context) PackedAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + FD->addAttr(::new (S.Context) PackedAttr(S.Context, AL)); } } else @@ -1408,9 +1357,7 @@ static void handleIBOutlet(Sema &S, Decl *D, const ParsedAttr &AL) { if (!checkIBOutletCommon(S, D, AL)) return; - D->addAttr(::new (S.Context) - IBOutletAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) IBOutletAttr(S.Context, AL)); } static void handleIBOutletCollection(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -1453,9 +1400,7 @@ static void handleIBOutletCollection(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) - IBOutletCollectionAttr(AL.getRange(), S.Context, QTLoc, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) IBOutletCollectionAttr(S.Context, AL, QTLoc)); } bool Sema::isValidPointerAttrType(QualType T, bool RefOkay) { @@ -1538,9 +1483,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ParamIdx *Start = NonNullArgs.data(); unsigned Size = NonNullArgs.size(); llvm::array_pod_sort(Start, Start + Size); - D->addAttr(::new (S.Context) - NonNullAttr(AL.getRange(), S.Context, Start, Size, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) NonNullAttr(S.Context, AL, Start, Size)); } static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D, @@ -1560,9 +1503,7 @@ static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D, D->getSourceRange())) return; - D->addAttr(::new (S.Context) - NonNullAttr(AL.getRange(), S.Context, nullptr, 0, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) NonNullAttr(S.Context, AL, nullptr, 0)); } static void handleReturnsNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -1572,9 +1513,7 @@ static void handleReturnsNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) { /* isReturnValue */ true)) return; - D->addAttr(::new (S.Context) - ReturnsNonNullAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ReturnsNonNullAttr(S.Context, AL)); } static void handleNoEscapeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -1589,33 +1528,30 @@ static void handleNoEscapeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) NoEscapeAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) NoEscapeAttr(S.Context, AL)); } static void handleAssumeAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { Expr *E = AL.getArgAsExpr(0), *OE = AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr; - S.AddAssumeAlignedAttr(AL.getRange(), D, E, OE, - AL.getAttributeSpellingListIndex()); + S.AddAssumeAlignedAttr(D, AL, E, OE); } static void handleAllocAlignAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - S.AddAllocAlignAttr(AL.getRange(), D, AL.getArgAsExpr(0), - AL.getAttributeSpellingListIndex()); + S.AddAllocAlignAttr(D, AL, AL.getArgAsExpr(0)); } -void Sema::AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, - Expr *OE, unsigned SpellingListIndex) { +void Sema::AddAssumeAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, + Expr *OE) { QualType ResultType = getFunctionOrMethodResultType(D); SourceRange SR = getFunctionOrMethodResultSourceRange(D); - AssumeAlignedAttr TmpAttr(AttrRange, Context, E, OE, SpellingListIndex); - SourceLocation AttrLoc = AttrRange.getBegin(); + AssumeAlignedAttr TmpAttr(Context, CI, E, OE); + SourceLocation AttrLoc = TmpAttr.getLocation(); if (!isValidPointerAttrType(ResultType, /* RefOkay */ true)) { Diag(AttrLoc, diag::warn_attribute_return_pointers_refs_only) - << &TmpAttr << AttrRange << SR; + << &TmpAttr << TmpAttr.getRange() << SR; return; } @@ -1652,21 +1588,20 @@ void Sema::AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, } } - D->addAttr(::new (Context) - AssumeAlignedAttr(AttrRange, Context, E, OE, SpellingListIndex)); + D->addAttr(::new (Context) AssumeAlignedAttr(Context, CI, E, OE)); } -void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr, - unsigned SpellingListIndex) { +void Sema::AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI, + Expr *ParamExpr) { QualType ResultType = getFunctionOrMethodResultType(D); - AllocAlignAttr TmpAttr(AttrRange, Context, ParamIdx(), SpellingListIndex); - SourceLocation AttrLoc = AttrRange.getBegin(); + AllocAlignAttr TmpAttr(Context, CI, ParamIdx()); + SourceLocation AttrLoc = CI.getLoc(); if (!ResultType->isDependentType() && !isValidPointerAttrType(ResultType, /* RefOkay */ true)) { Diag(AttrLoc, diag::warn_attribute_return_pointers_refs_only) - << &TmpAttr << AttrRange << getFunctionOrMethodResultSourceRange(D); + << &TmpAttr << CI.getRange() << getFunctionOrMethodResultSourceRange(D); return; } @@ -1684,8 +1619,7 @@ void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr, return; } - D->addAttr(::new (Context) - AllocAlignAttr(AttrRange, Context, Idx, SpellingListIndex)); + D->addAttr(::new (Context) AllocAlignAttr(Context, CI, Idx)); } /// Normalize the attribute, __foo__ becomes foo. @@ -1716,8 +1650,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Figure out our Kind. OwnershipAttr::OwnershipKind K = - OwnershipAttr(AL.getLoc(), S.Context, nullptr, nullptr, 0, - AL.getAttributeSpellingListIndex()).getOwnKind(); + OwnershipAttr(S.Context, AL, nullptr, nullptr, 0).getOwnKind(); // Check arguments. switch (K) { @@ -1799,8 +1732,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { unsigned Size = OwnershipArgs.size(); llvm::array_pod_sort(Start, Start + Size); D->addAttr(::new (S.Context) - OwnershipAttr(AL.getLoc(), S.Context, Module, Start, Size, - AL.getAttributeSpellingListIndex())); + OwnershipAttr(S.Context, AL, Module, Start, Size)); } static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -1856,12 +1788,9 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (AL.getNumArgs() && S.checkStringLiteralArgumentAttr(AL, 0, Str)) // GCC will accept anything as the argument of weakref. Should we // check for an existing decl? - D->addAttr(::new (S.Context) AliasAttr(AL.getRange(), S.Context, Str, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str)); - D->addAttr(::new (S.Context) - WeakRefAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) WeakRefAttr(S.Context, AL)); } static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -1876,8 +1805,7 @@ static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) IFuncAttr(AL.getRange(), S.Context, Str, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) IFuncAttr(S.Context, AL, Str)); } static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -1918,8 +1846,7 @@ static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ND->markUsed(S.Context); } - D->addAttr(::new (S.Context) AliasAttr(AL.getRange(), S.Context, Str, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str)); } static void handleTLSModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -1936,16 +1863,13 @@ static void handleTLSModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) - TLSModelAttr(AL.getRange(), S.Context, Model, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) TLSModelAttr(S.Context, AL, Model)); } static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) { QualType ResultType = getFunctionOrMethodResultType(D); if (ResultType->isAnyPointerType() || ResultType->isBlockPointerType()) { - D->addAttr(::new (S.Context) RestrictAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) RestrictAttr(S.Context, AL)); return; } @@ -1996,13 +1920,11 @@ static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) { FD->setIsMultiVersion(true); if (AL.getKind() == ParsedAttr::AT_CPUSpecific) - D->addAttr(::new (S.Context) CPUSpecificAttr( - AL.getRange(), S.Context, CPUs.data(), CPUs.size(), - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + CPUSpecificAttr(S.Context, AL, CPUs.data(), CPUs.size())); else - D->addAttr(::new (S.Context) CPUDispatchAttr( - AL.getRange(), S.Context, CPUs.data(), CPUs.size(), - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + CPUDispatchAttr(S.Context, AL, CPUs.data(), CPUs.size())); } static void handleCommonAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -2031,8 +1953,7 @@ static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } - D->addAttr(::new (S.Context) NakedAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) NakedAttr(S.Context, AL)); } static void handleNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) { @@ -2044,8 +1965,7 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) { return; } - D->addAttr(::new (S.Context) NoReturnAttr( - Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) NoReturnAttr(S.Context, Attrs)); } static void handleNoCfCheckAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) { @@ -2091,9 +2011,7 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } - D->addAttr(::new (S.Context) - AnalyzerNoReturnAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(S.Context, AL)); } // PS3 PPU-specific. @@ -2148,8 +2066,7 @@ static void handleVecReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) { count++; } - D->addAttr(::new (S.Context) VecReturnAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) VecReturnAttr(S.Context, AL)); } static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D, @@ -2164,9 +2081,7 @@ static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D, } } - D->addAttr(::new (S.Context) CarriesDependencyAttr( - AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) CarriesDependencyAttr(S.Context, AL)); } static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -2177,8 +2092,7 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.getLangOpts().CPlusPlus17 && IsCXX17Attr) S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL; - D->addAttr(::new (S.Context) UnusedAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL)); } static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -2187,9 +2101,7 @@ static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority)) return; - D->addAttr(::new (S.Context) - ConstructorAttr(AL.getRange(), S.Context, priority, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority)); } static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -2198,9 +2110,7 @@ static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority)) return; - D->addAttr(::new (S.Context) - DestructorAttr(AL.getRange(), S.Context, priority, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority)); } template <typename AttrTy> @@ -2210,8 +2120,7 @@ static void handleAttrWithMessage(Sema &S, Decl *D, const ParsedAttr &AL) { if (AL.getNumArgs() == 1 && !S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; - D->addAttr(::new (S.Context) AttrTy(AL.getRange(), S.Context, Str, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AttrTy(S.Context, AL, Str)); } static void handleObjCSuppresProtocolAttr(Sema &S, Decl *D, @@ -2222,9 +2131,7 @@ static void handleObjCSuppresProtocolAttr(Sema &S, Decl *D, return; } - D->addAttr(::new (S.Context) - ObjCExplicitProtocolImplAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ObjCExplicitProtocolImplAttr(S.Context, AL)); } static bool checkAvailabilityAttr(Sema &S, SourceRange Range, @@ -2285,10 +2192,11 @@ static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y, } AvailabilityAttr *Sema::mergeAvailabilityAttr( - NamedDecl *D, SourceRange Range, IdentifierInfo *Platform, bool Implicit, - VersionTuple Introduced, VersionTuple Deprecated, VersionTuple Obsoleted, - bool IsUnavailable, StringRef Message, bool IsStrict, StringRef Replacement, - AvailabilityMergeKind AMK, int Priority, unsigned AttrSpellingListIndex) { + NamedDecl *D, const AttributeCommonInfo &CI, IdentifierInfo *Platform, + bool Implicit, VersionTuple Introduced, VersionTuple Deprecated, + VersionTuple Obsoleted, bool IsUnavailable, StringRef Message, + bool IsStrict, StringRef Replacement, AvailabilityMergeKind AMK, + int Priority) { VersionTuple MergedIntroduced = Introduced; VersionTuple MergedDeprecated = Deprecated; VersionTuple MergedObsoleted = Obsoleted; @@ -2379,12 +2287,12 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr( << (AMK == AMK_Override); } if (AMK == AMK_Override) - Diag(Range.getBegin(), diag::note_overridden_method); + Diag(CI.getLoc(), diag::note_overridden_method); else - Diag(Range.getBegin(), diag::note_protocol_method); + Diag(CI.getLoc(), diag::note_protocol_method); } else { Diag(OldAA->getLocation(), diag::warn_mismatched_availability); - Diag(Range.getBegin(), diag::note_previous_attribute); + Diag(CI.getLoc(), diag::note_previous_attribute); } Attrs.erase(Attrs.begin() + i); @@ -2426,13 +2334,12 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr( // Only create a new attribute if !OverrideOrImpl, but we want to do // the checking. - if (!checkAvailabilityAttr(*this, Range, Platform, MergedIntroduced, + if (!checkAvailabilityAttr(*this, CI.getRange(), Platform, MergedIntroduced, MergedDeprecated, MergedObsoleted) && !OverrideOrImpl) { - auto *Avail = ::new (Context) - AvailabilityAttr(Range, Context, Platform, Introduced, Deprecated, - Obsoleted, IsUnavailable, Message, IsStrict, - Replacement, Priority, AttrSpellingListIndex); + auto *Avail = ::new (Context) AvailabilityAttr( + Context, CI, Platform, Introduced, Deprecated, Obsoleted, IsUnavailable, + Message, IsStrict, Replacement, Priority); Avail->setImplicit(Implicit); return Avail; } @@ -2443,7 +2350,6 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!checkAttributeNumArgs(S, AL, 1)) return; IdentifierLoc *Platform = AL.getArgAsIdent(0); - unsigned Index = AL.getAttributeSpellingListIndex(); IdentifierInfo *II = Platform->Ident; if (AvailabilityAttr::getPrettyPlatformName(II->getName()).empty()) @@ -2479,9 +2385,9 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ? Sema::AP_PragmaClangAttribute : Sema::AP_Explicit; AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( - ND, AL.getRange(), II, false /*Implicit*/, Introduced.Version, - Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, IsStrict, - Replacement, Sema::AMK_None, PriorityModifier, Index); + ND, AL, II, false /*Implicit*/, Introduced.Version, Deprecated.Version, + Obsoleted.Version, IsUnavailable, Str, IsStrict, Replacement, + Sema::AMK_None, PriorityModifier); if (NewAttr) D->addAttr(NewAttr); @@ -2519,10 +2425,10 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version); AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( - ND, AL.getRange(), NewII, true /*Implicit*/, NewIntroduced, - NewDeprecated, NewObsoleted, IsUnavailable, Str, IsStrict, - Replacement, Sema::AMK_None, - PriorityModifier + Sema::AP_InferredFromOtherPlatform, Index); + ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated, + NewObsoleted, IsUnavailable, Str, IsStrict, Replacement, + Sema::AMK_None, + PriorityModifier + Sema::AP_InferredFromOtherPlatform); if (NewAttr) D->addAttr(NewAttr); } @@ -2537,10 +2443,10 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (NewII) { AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( - ND, AL.getRange(), NewII, true /*Implicit*/, Introduced.Version, + ND, AL, NewII, true /*Implicit*/, Introduced.Version, Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, IsStrict, Replacement, Sema::AMK_None, - PriorityModifier + Sema::AP_InferredFromOtherPlatform, Index); + PriorityModifier + Sema::AP_InferredFromOtherPlatform); if (NewAttr) D->addAttr(NewAttr); } @@ -2563,38 +2469,34 @@ static void handleExternalSourceSymbolAttr(Sema &S, Decl *D, bool IsGeneratedDeclaration = AL.getArgAsIdent(2) != nullptr; D->addAttr(::new (S.Context) ExternalSourceSymbolAttr( - AL.getRange(), S.Context, Language, DefinedIn, IsGeneratedDeclaration, - AL.getAttributeSpellingListIndex())); + S.Context, AL, Language, DefinedIn, IsGeneratedDeclaration)); } template <class T> -static T *mergeVisibilityAttr(Sema &S, Decl *D, SourceRange range, - typename T::VisibilityType value, - unsigned attrSpellingListIndex) { +static T *mergeVisibilityAttr(Sema &S, Decl *D, const AttributeCommonInfo &CI, + typename T::VisibilityType value) { T *existingAttr = D->getAttr<T>(); if (existingAttr) { typename T::VisibilityType existingValue = existingAttr->getVisibility(); if (existingValue == value) return nullptr; S.Diag(existingAttr->getLocation(), diag::err_mismatched_visibility); - S.Diag(range.getBegin(), diag::note_previous_attribute); + S.Diag(CI.getLoc(), diag::note_previous_attribute); D->dropAttr<T>(); } - return ::new (S.Context) T(range, S.Context, value, attrSpellingListIndex); + return ::new (S.Context) T(S.Context, CI, value); } -VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D, SourceRange Range, - VisibilityAttr::VisibilityType Vis, - unsigned AttrSpellingListIndex) { - return ::mergeVisibilityAttr<VisibilityAttr>(*this, D, Range, Vis, - AttrSpellingListIndex); +VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D, + const AttributeCommonInfo &CI, + VisibilityAttr::VisibilityType Vis) { + return ::mergeVisibilityAttr<VisibilityAttr>(*this, D, CI, Vis); } -TypeVisibilityAttr *Sema::mergeTypeVisibilityAttr(Decl *D, SourceRange Range, - TypeVisibilityAttr::VisibilityType Vis, - unsigned AttrSpellingListIndex) { - return ::mergeVisibilityAttr<TypeVisibilityAttr>(*this, D, Range, Vis, - AttrSpellingListIndex); +TypeVisibilityAttr * +Sema::mergeTypeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI, + TypeVisibilityAttr::VisibilityType Vis) { + return ::mergeVisibilityAttr<TypeVisibilityAttr>(*this, D, CI, Vis); } static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL, @@ -2636,14 +2538,12 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL, type = VisibilityAttr::Default; } - unsigned Index = AL.getAttributeSpellingListIndex(); Attr *newAttr; if (isTypeVisibility) { - newAttr = S.mergeTypeVisibilityAttr(D, AL.getRange(), - (TypeVisibilityAttr::VisibilityType) type, - Index); + newAttr = S.mergeTypeVisibilityAttr( + D, AL, (TypeVisibilityAttr::VisibilityType)type); } else { - newAttr = S.mergeVisibilityAttr(D, AL.getRange(), type, Index); + newAttr = S.mergeVisibilityAttr(D, AL, type); } if (newAttr) D->addAttr(newAttr); @@ -2672,8 +2572,7 @@ static void handleObjCMethodFamilyAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(new (S.Context) ObjCMethodFamilyAttr( - AL.getRange(), S.Context, F, AL.getAttributeSpellingListIndex())); + D->addAttr(new (S.Context) ObjCMethodFamilyAttr(S.Context, AL, F)); } static void handleObjCNSObject(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -2700,9 +2599,7 @@ static void handleObjCNSObject(Sema &S, Decl *D, const ParsedAttr &AL) { // case. S.Diag(D->getLocation(), diag::warn_nsobject_attribute); } - D->addAttr(::new (S.Context) - ObjCNSObjectAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ObjCNSObjectAttr(S.Context, AL)); } static void handleObjCIndependentClass(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -2716,9 +2613,7 @@ static void handleObjCIndependentClass(Sema &S, Decl *D, const ParsedAttr &AL) { S.Diag(D->getLocation(), diag::warn_independentclass_attribute); return; } - D->addAttr(::new (S.Context) - ObjCIndependentClassAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ObjCIndependentClassAttr(S.Context, AL)); } static void handleBlocksAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -2735,9 +2630,7 @@ static void handleBlocksAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) - BlocksAttr(AL.getRange(), S.Context, type, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) BlocksAttr(S.Context, AL, type)); } static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -2808,7 +2701,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) { const FunctionType *FT = Ty->isFunctionPointerType() ? D->getFunctionType() - : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>(); + : Ty->castAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>(); if (!cast<FunctionProtoType>(FT)->isVariadic()) { int m = Ty->isFunctionPointerType() ? 0 : 1; S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m; @@ -2824,14 +2717,13 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { << AL << ExpectedFunctionMethodOrBlock; return; } - D->addAttr(::new (S.Context) - SentinelAttr(AL.getRange(), S.Context, sentinel, nullPos, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) SentinelAttr(S.Context, AL, sentinel, nullPos)); } static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) { if (D->getFunctionType() && - D->getFunctionType()->getReturnType()->isVoidType()) { + D->getFunctionType()->getReturnType()->isVoidType() && + !isa<CXXConstructorDecl>(D)) { S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) << AL << 0; return; } @@ -2841,15 +2733,29 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - // If this is spelled as the standard C++17 attribute, but not in C++17, warn - // about using it as an extension. - if (!S.getLangOpts().CPlusPlus17 && AL.isCXX11Attribute() && - !AL.getScopeName()) - S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL; + StringRef Str; + if ((AL.isCXX11Attribute() || AL.isC2xAttribute()) && !AL.getScopeName()) { + // If this is spelled as the standard C++17 attribute, but not in C++17, + // warn about using it as an extension. If there are attribute arguments, + // then claim it's a C++2a extension instead. + // FIXME: If WG14 does not seem likely to adopt the same feature, add an + // extension warning for C2x mode. + const LangOptions &LO = S.getLangOpts(); + if (AL.getNumArgs() == 1) { + if (LO.CPlusPlus && !LO.CPlusPlus2a) + S.Diag(AL.getLoc(), diag::ext_cxx2a_attr) << AL; + + // Since this this is spelled [[nodiscard]], get the optional string + // literal. If in C++ mode, but not in C++2a mode, diagnose as an + // extension. + // FIXME: C2x should support this feature as well, even as an extension. + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, nullptr)) + return; + } else if (LO.CPlusPlus && !LO.CPlusPlus17) + S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL; + } - D->addAttr(::new (S.Context) - WarnUnusedResultAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) WarnUnusedResultAttr(S.Context, AL, Str)); } static void handleWeakImportAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -2870,9 +2776,7 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) - WeakImportAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) WeakImportAttr(S.Context, AL)); } // Handles reqd_work_group_size and work_group_size_hint. @@ -2897,9 +2801,8 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { Existing->getZDim() == WGSize[2])) S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; - D->addAttr(::new (S.Context) WorkGroupAttr(AL.getRange(), S.Context, - WGSize[0], WGSize[1], WGSize[2], - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + WorkGroupAttr(S.Context, AL, WGSize[0], WGSize[1], WGSize[2])); } // Handles intel_reqd_sub_group_size. @@ -2919,9 +2822,8 @@ static void handleSubGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { if (Existing && Existing->getSubGroupSize() != SGSize) S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; - D->addAttr(::new (S.Context) OpenCLIntelReqdSubGroupSizeAttr( - AL.getRange(), S.Context, SGSize, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + OpenCLIntelReqdSubGroupSizeAttr(S.Context, AL, SGSize)); } static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -2937,8 +2839,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_argument_vec_type_hint) - << ParmType; + S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument) << 3 << AL; return; } @@ -2949,18 +2850,15 @@ static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) { } } - D->addAttr(::new (S.Context) VecTypeHintAttr(AL.getLoc(), S.Context, - ParmTSI, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) VecTypeHintAttr(S.Context, AL, ParmTSI)); } -SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range, - StringRef Name, - unsigned AttrSpellingListIndex) { +SectionAttr *Sema::mergeSectionAttr(Decl *D, const AttributeCommonInfo &CI, + StringRef Name) { // Explicit or partial specializations do not inherit // the section attribute from the primary template. if (const auto *FD = dyn_cast<FunctionDecl>(D)) { - if (AttrSpellingListIndex == SectionAttr::Declspec_allocate && + if (CI.getAttributeSpellingListIndex() == SectionAttr::Declspec_allocate && FD->isFunctionTemplateSpecialization()) return nullptr; } @@ -2969,11 +2867,10 @@ SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range, return nullptr; Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section) << 1 /*section*/; - Diag(Range.getBegin(), diag::note_previous_attribute); + Diag(CI.getLoc(), diag::note_previous_attribute); return nullptr; } - return ::new (Context) SectionAttr(Range, Context, Name, - AttrSpellingListIndex); + return ::new (Context) SectionAttr(Context, CI, Name); } bool Sema::checkSectionName(SourceLocation LiteralLoc, StringRef SecName) { @@ -3005,8 +2902,7 @@ static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - unsigned Index = AL.getAttributeSpellingListIndex(); - SectionAttr *NewAttr = S.mergeSectionAttr(D, AL.getRange(), Str, Index); + SectionAttr *NewAttr = S.mergeSectionAttr(D, AL, Str); if (NewAttr) D->addAttr(NewAttr); } @@ -3026,9 +2922,8 @@ static bool checkCodeSegName(Sema &S, SourceLocation LiteralLoc, return true; } -CodeSegAttr *Sema::mergeCodeSegAttr(Decl *D, SourceRange Range, - StringRef Name, - unsigned AttrSpellingListIndex) { +CodeSegAttr *Sema::mergeCodeSegAttr(Decl *D, const AttributeCommonInfo &CI, + StringRef Name) { // Explicit or partial specializations do not inherit // the code_seg attribute from the primary template. if (const auto *FD = dyn_cast<FunctionDecl>(D)) { @@ -3040,11 +2935,10 @@ CodeSegAttr *Sema::mergeCodeSegAttr(Decl *D, SourceRange Range, return nullptr; Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section) << 0 /*codeseg*/; - Diag(Range.getBegin(), diag::note_previous_attribute); + Diag(CI.getLoc(), diag::note_previous_attribute); return nullptr; } - return ::new (Context) CodeSegAttr(Range, Context, Name, - AttrSpellingListIndex); + return ::new (Context) CodeSegAttr(Context, CI, Name); } static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -3064,8 +2958,7 @@ static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } D->dropAttr<CodeSegAttr>(); } - if (CodeSegAttr *CSA = S.mergeCodeSegAttr(D, AL.getRange(), Str, - AL.getAttributeSpellingListIndex())) + if (CodeSegAttr *CSA = S.mergeCodeSegAttr(D, AL, Str)) D->addAttr(CSA); } @@ -3107,9 +3000,7 @@ static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.checkTargetAttr(LiteralLoc, Str)) return; - unsigned Index = AL.getAttributeSpellingListIndex(); - TargetAttr *NewAttr = - ::new (S.Context) TargetAttr(AL.getRange(), S.Context, Str, Index); + TargetAttr *NewAttr = ::new (S.Context) TargetAttr(S.Context, AL, Str); D->addAttr(NewAttr); } @@ -3127,9 +3018,7 @@ static void handleMinVectorWidthAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) - MinVectorWidthAttr(AL.getRange(), S.Context, VecWidth, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) MinVectorWidthAttr(S.Context, AL, VecWidth)); } static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -3184,9 +3073,7 @@ static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) - CleanupAttr(AL.getRange(), S.Context, FD, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) CleanupAttr(S.Context, AL, FD)); } static void handleEnumExtensibilityAttr(Sema &S, Decl *D, @@ -3205,9 +3092,8 @@ static void handleEnumExtensibilityAttr(Sema &S, Decl *D, return; } - D->addAttr(::new (S.Context) EnumExtensibilityAttr( - AL.getRange(), S.Context, ExtensibilityKind, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + EnumExtensibilityAttr(S.Context, AL, ExtensibilityKind)); } /// Handle __attribute__((format_arg((idx)))) attribute based on @@ -3225,7 +3111,7 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (NotNSStringTy && !isCFStringType(Ty, S.Context) && (!Ty->isPointerType() || - !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) { + !Ty->castAs<PointerType>()->getPointeeType()->isCharType())) { S.Diag(AL.getLoc(), diag::err_format_attribute_not) << "a string type" << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0); @@ -3235,15 +3121,14 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isNSStringType(Ty, S.Context) && !isCFStringType(Ty, S.Context) && (!Ty->isPointerType() || - !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) { + !Ty->castAs<PointerType>()->getPointeeType()->isCharType())) { S.Diag(AL.getLoc(), diag::err_format_attribute_result_not) << (NotNSStringTy ? "string type" : "NSString") << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0); return; } - D->addAttr(::new (S.Context) FormatArgAttr( - AL.getRange(), S.Context, Idx, AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) FormatArgAttr(S.Context, AL, Idx)); } enum FormatAttrKind { @@ -3311,15 +3196,12 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { AL.setInvalid(); return; } - D->addAttr(::new (S.Context) - InitPriorityAttr(AL.getRange(), S.Context, prioritynum, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) InitPriorityAttr(S.Context, AL, prioritynum)); } -FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range, +FormatAttr *Sema::mergeFormatAttr(Decl *D, const AttributeCommonInfo &CI, IdentifierInfo *Format, int FormatIdx, - int FirstArg, - unsigned AttrSpellingListIndex) { + int FirstArg) { // Check whether we already have an equivalent format attribute. for (auto *F : D->specific_attrs<FormatAttr>()) { if (F->getType() == Format && @@ -3328,13 +3210,12 @@ FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range, // If we don't have a valid location for this attribute, adopt the // location. if (F->getLocation().isInvalid()) - F->setRange(Range); + F->setRange(CI.getRange()); return nullptr; } } - return ::new (Context) FormatAttr(Range, Context, Format, FormatIdx, - FirstArg, AttrSpellingListIndex); + return ::new (Context) FormatAttr(Context, CI, Format, FormatIdx, FirstArg); } /// Handle __attribute__((format(type,idx,firstarg))) attributes based on @@ -3416,7 +3297,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } } else if (!Ty->isPointerType() || - !Ty->getAs<PointerType>()->getPointeeType()->isCharType()) { + !Ty->castAs<PointerType>()->getPointeeType()->isCharType()) { S.Diag(AL.getLoc(), diag::err_format_attribute_not) << "a string type" << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, ArgIdx); @@ -3454,9 +3335,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - FormatAttr *NewAttr = S.mergeFormatAttr(D, AL.getRange(), II, - Idx, FirstArg, - AL.getAttributeSpellingListIndex()); + FormatAttr *NewAttr = S.mergeFormatAttr(D, AL, II, Idx, FirstArg); if (NewAttr) D->addAttr(NewAttr); } @@ -3597,8 +3476,7 @@ static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } D->addAttr(::new (S.Context) CallbackAttr( - AL.getRange(), S.Context, EncodingIndices.data(), EncodingIndices.size(), - AL.getAttributeSpellingListIndex())); + S.Context, AL, EncodingIndices.data(), EncodingIndices.size())); } static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -3669,9 +3547,7 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } - RD->addAttr(::new (S.Context) - TransparentUnionAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + RD->addAttr(::new (S.Context) TransparentUnionAttr(S.Context, AL)); } static void handleAnnotateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -3687,20 +3563,16 @@ static void handleAnnotateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) - AnnotateAttr(AL.getRange(), S.Context, Str, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AnnotateAttr(S.Context, AL, Str)); } static void handleAlignValueAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - S.AddAlignValueAttr(AL.getRange(), D, AL.getArgAsExpr(0), - AL.getAttributeSpellingListIndex()); + S.AddAlignValueAttr(D, AL, AL.getArgAsExpr(0)); } -void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, - unsigned SpellingListIndex) { - AlignValueAttr TmpAttr(AttrRange, Context, E, SpellingListIndex); - SourceLocation AttrLoc = AttrRange.getBegin(); +void Sema::AddAlignValueAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E) { + AlignValueAttr TmpAttr(Context, CI, E); + SourceLocation AttrLoc = CI.getLoc(); QualType T; if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) @@ -3732,14 +3604,12 @@ void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, return; } - D->addAttr(::new (Context) - AlignValueAttr(AttrRange, Context, ICE.get(), - SpellingListIndex)); + D->addAttr(::new (Context) AlignValueAttr(Context, CI, ICE.get())); return; } // Save dependent expressions in the AST to be instantiated. - D->addAttr(::new (Context) AlignValueAttr(TmpAttr)); + D->addAttr(::new (Context) AlignValueAttr(Context, CI, E)); } static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -3750,8 +3620,7 @@ static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } if (AL.getNumArgs() == 0) { - D->addAttr(::new (S.Context) AlignedAttr(AL.getRange(), S.Context, - true, nullptr, AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AlignedAttr(S.Context, AL, true, nullptr)); return; } @@ -3765,14 +3634,13 @@ static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.isPackExpansion() && S.DiagnoseUnexpandedParameterPack(E)) return; - S.AddAlignedAttr(AL.getRange(), D, E, AL.getAttributeSpellingListIndex(), - AL.isPackExpansion()); + S.AddAlignedAttr(D, AL, E, AL.isPackExpansion()); } -void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, - unsigned SpellingListIndex, bool IsPackExpansion) { - AlignedAttr TmpAttr(AttrRange, Context, true, E, SpellingListIndex); - SourceLocation AttrLoc = AttrRange.getBegin(); +void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, + bool IsPackExpansion) { + AlignedAttr TmpAttr(Context, CI, true, E); + SourceLocation AttrLoc = CI.getLoc(); // C++11 alignas(...) and C11 _Alignas(...) have additional requirements. if (TmpAttr.isAlignas()) { @@ -3824,7 +3692,7 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, } // Save dependent expressions in the AST to be instantiated. - AlignedAttr *AA = ::new (Context) AlignedAttr(TmpAttr); + AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, true, E); AA->setPackExpansion(IsPackExpansion); D->addAttr(AA); return; @@ -3877,18 +3745,16 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, } } - AlignedAttr *AA = ::new (Context) AlignedAttr(AttrRange, Context, true, - ICE.get(), SpellingListIndex); + AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, true, ICE.get()); AA->setPackExpansion(IsPackExpansion); D->addAttr(AA); } -void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS, - unsigned SpellingListIndex, bool IsPackExpansion) { +void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, + TypeSourceInfo *TS, bool IsPackExpansion) { // FIXME: Cache the number on the AL object if non-dependent? // FIXME: Perform checking of type validity - AlignedAttr *AA = ::new (Context) AlignedAttr(AttrRange, Context, false, TS, - SpellingListIndex); + AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, false, TS); AA->setPackExpansion(IsPackExpansion); D->addAttr(AA); } @@ -4032,14 +3898,14 @@ static void handleModeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { IdentifierInfo *Name = AL.getArgAsIdent(0)->Ident; - S.AddModeAttr(AL.getRange(), D, Name, AL.getAttributeSpellingListIndex()); + S.AddModeAttr(D, AL, Name); } -void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, - unsigned SpellingListIndex, bool InInstantiation) { +void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI, + IdentifierInfo *Name, bool InInstantiation) { StringRef Str = Name->getName(); normalizeName(Str); - SourceLocation AttrLoc = AttrRange.getBegin(); + SourceLocation AttrLoc = CI.getLoc(); unsigned DestWidth = 0; bool IntegerMode = true; @@ -4090,8 +3956,7 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, OldTy = cast<ValueDecl>(D)->getType(); if (OldTy->isDependentType()) { - D->addAttr(::new (Context) - ModeAttr(AttrRange, Context, Name, SpellingListIndex)); + D->addAttr(::new (Context) ModeAttr(Context, CI, Name)); return; } @@ -4106,7 +3971,7 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, // type, 'enum { A } __attribute__((mode(V4SI)))' is rejected. if ((isa<EnumDecl>(D) || OldElemTy->getAs<EnumType>()) && VectorSize.getBoolValue()) { - Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << AttrRange; + Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << CI.getRange(); return; } bool IntegralOrAnyEnumType = @@ -4173,21 +4038,18 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, else cast<ValueDecl>(D)->setType(NewTy); - D->addAttr(::new (Context) - ModeAttr(AttrRange, Context, Name, SpellingListIndex)); + D->addAttr(::new (Context) ModeAttr(Context, CI, Name)); } static void handleNoDebugAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - D->addAttr(::new (S.Context) - NoDebugAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) NoDebugAttr(S.Context, AL)); } -AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D, SourceRange Range, - IdentifierInfo *Ident, - unsigned AttrSpellingListIndex) { +AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D, + const AttributeCommonInfo &CI, + const IdentifierInfo *Ident) { if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) { - Diag(Range.getBegin(), diag::warn_attribute_ignored) << Ident; + Diag(CI.getLoc(), diag::warn_attribute_ignored) << Ident; Diag(Optnone->getLocation(), diag::note_conflicting_attribute); return nullptr; } @@ -4195,24 +4057,21 @@ AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D, SourceRange Range, if (D->hasAttr<AlwaysInlineAttr>()) return nullptr; - return ::new (Context) AlwaysInlineAttr(Range, Context, - AttrSpellingListIndex); + return ::new (Context) AlwaysInlineAttr(Context, CI); } CommonAttr *Sema::mergeCommonAttr(Decl *D, const ParsedAttr &AL) { if (checkAttrMutualExclusion<InternalLinkageAttr>(*this, D, AL)) return nullptr; - return ::new (Context) - CommonAttr(AL.getRange(), Context, AL.getAttributeSpellingListIndex()); + return ::new (Context) CommonAttr(Context, AL); } CommonAttr *Sema::mergeCommonAttr(Decl *D, const CommonAttr &AL) { if (checkAttrMutualExclusion<InternalLinkageAttr>(*this, D, AL)) return nullptr; - return ::new (Context) - CommonAttr(AL.getRange(), Context, AL.getSpellingListIndex()); + return ::new (Context) CommonAttr(Context, AL); } InternalLinkageAttr *Sema::mergeInternalLinkageAttr(Decl *D, @@ -4236,8 +4095,7 @@ InternalLinkageAttr *Sema::mergeInternalLinkageAttr(Decl *D, if (checkAttrMutualExclusion<CommonAttr>(*this, D, AL)) return nullptr; - return ::new (Context) InternalLinkageAttr( - AL.getRange(), Context, AL.getAttributeSpellingListIndex()); + return ::new (Context) InternalLinkageAttr(Context, AL); } InternalLinkageAttr * Sema::mergeInternalLinkageAttr(Decl *D, const InternalLinkageAttr &AL) { @@ -4260,14 +4118,12 @@ Sema::mergeInternalLinkageAttr(Decl *D, const InternalLinkageAttr &AL) { if (checkAttrMutualExclusion<CommonAttr>(*this, D, AL)) return nullptr; - return ::new (Context) - InternalLinkageAttr(AL.getRange(), Context, AL.getSpellingListIndex()); + return ::new (Context) InternalLinkageAttr(Context, AL); } -MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range, - unsigned AttrSpellingListIndex) { +MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, const AttributeCommonInfo &CI) { if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) { - Diag(Range.getBegin(), diag::warn_attribute_ignored) << "'minsize'"; + Diag(CI.getLoc(), diag::warn_attribute_ignored) << "'minsize'"; Diag(Optnone->getLocation(), diag::note_conflicting_attribute); return nullptr; } @@ -4275,7 +4131,7 @@ MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range, if (D->hasAttr<MinSizeAttr>()) return nullptr; - return ::new (Context) MinSizeAttr(Range, Context, AttrSpellingListIndex); + return ::new (Context) MinSizeAttr(Context, CI); } NoSpeculativeLoadHardeningAttr *Sema::mergeNoSpeculativeLoadHardeningAttr( @@ -4283,28 +4139,26 @@ NoSpeculativeLoadHardeningAttr *Sema::mergeNoSpeculativeLoadHardeningAttr( if (checkAttrMutualExclusion<SpeculativeLoadHardeningAttr>(*this, D, AL)) return nullptr; - return ::new (Context) NoSpeculativeLoadHardeningAttr( - AL.getRange(), Context, AL.getSpellingListIndex()); + return ::new (Context) NoSpeculativeLoadHardeningAttr(Context, AL); } -OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range, - unsigned AttrSpellingListIndex) { +OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, + const AttributeCommonInfo &CI) { if (AlwaysInlineAttr *Inline = D->getAttr<AlwaysInlineAttr>()) { Diag(Inline->getLocation(), diag::warn_attribute_ignored) << Inline; - Diag(Range.getBegin(), diag::note_conflicting_attribute); + Diag(CI.getLoc(), diag::note_conflicting_attribute); D->dropAttr<AlwaysInlineAttr>(); } if (MinSizeAttr *MinSize = D->getAttr<MinSizeAttr>()) { Diag(MinSize->getLocation(), diag::warn_attribute_ignored) << MinSize; - Diag(Range.getBegin(), diag::note_conflicting_attribute); + Diag(CI.getLoc(), diag::note_conflicting_attribute); D->dropAttr<MinSizeAttr>(); } if (D->hasAttr<OptimizeNoneAttr>()) return nullptr; - return ::new (Context) OptimizeNoneAttr(Range, Context, - AttrSpellingListIndex); + return ::new (Context) OptimizeNoneAttr(Context, CI); } SpeculativeLoadHardeningAttr *Sema::mergeSpeculativeLoadHardeningAttr( @@ -4312,29 +4166,25 @@ SpeculativeLoadHardeningAttr *Sema::mergeSpeculativeLoadHardeningAttr( if (checkAttrMutualExclusion<NoSpeculativeLoadHardeningAttr>(*this, D, AL)) return nullptr; - return ::new (Context) SpeculativeLoadHardeningAttr( - AL.getRange(), Context, AL.getSpellingListIndex()); + return ::new (Context) SpeculativeLoadHardeningAttr(Context, AL); } static void handleAlwaysInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, AL)) return; - if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr( - D, AL.getRange(), AL.getName(), - AL.getAttributeSpellingListIndex())) + if (AlwaysInlineAttr *Inline = + S.mergeAlwaysInlineAttr(D, AL, AL.getAttrName())) D->addAttr(Inline); } static void handleMinSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (MinSizeAttr *MinSize = S.mergeMinSizeAttr( - D, AL.getRange(), AL.getAttributeSpellingListIndex())) + if (MinSizeAttr *MinSize = S.mergeMinSizeAttr(D, AL)) D->addAttr(MinSize); } static void handleOptimizeNoneAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (OptimizeNoneAttr *Optnone = S.mergeOptimizeNoneAttr( - D, AL.getRange(), AL.getAttributeSpellingListIndex())) + if (OptimizeNoneAttr *Optnone = S.mergeOptimizeNoneAttr(D, AL)) D->addAttr(Optnone); } @@ -4346,8 +4196,7 @@ static void handleConstantAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.Diag(AL.getLoc(), diag::err_cuda_nonglobal_constant); return; } - D->addAttr(::new (S.Context) CUDAConstantAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) CUDAConstantAttr(S.Context, AL)); } static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -4365,8 +4214,7 @@ static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.CUDADiagIfHostCode(AL.getLoc(), diag::err_cuda_host_shared) << S.CurrentCUDATarget()) return; - D->addAttr(::new (S.Context) CUDASharedAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) CUDASharedAttr(S.Context, AL)); } static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -4375,7 +4223,9 @@ static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } const auto *FD = cast<FunctionDecl>(D); - if (!FD->getReturnType()->isVoidType()) { + if (!FD->getReturnType()->isVoidType() && + !FD->getReturnType()->getAs<AutoType>() && + !FD->getReturnType()->isInstantiationDependentType()) { SourceRange RTRange = FD->getReturnTypeSourceRange(); S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return) << FD->getType() @@ -4395,9 +4245,7 @@ static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (FD->isInlineSpecified() && !S.getLangOpts().CUDAIsDevice) S.Diag(FD->getBeginLoc(), diag::warn_kern_is_inline) << FD; - D->addAttr(::new (S.Context) - CUDAGlobalAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) CUDAGlobalAttr(S.Context, AL)); } static void handleGNUInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -4407,9 +4255,10 @@ static void handleGNUInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) - GNUInlineAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + if (S.LangOpts.CPlusPlus && Fn->getStorageClass() != SC_Extern) + S.Diag(AL.getLoc(), diag::warn_gnu_inline_cplusplus_without_extern); + + D->addAttr(::new (S.Context) GNUInlineAttr(S.Context, AL)); } static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -4429,53 +4278,34 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) { switch (AL.getKind()) { case ParsedAttr::AT_FastCall: - D->addAttr(::new (S.Context) - FastCallAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) FastCallAttr(S.Context, AL)); return; case ParsedAttr::AT_StdCall: - D->addAttr(::new (S.Context) - StdCallAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) StdCallAttr(S.Context, AL)); return; case ParsedAttr::AT_ThisCall: - D->addAttr(::new (S.Context) - ThisCallAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ThisCallAttr(S.Context, AL)); return; case ParsedAttr::AT_CDecl: - D->addAttr(::new (S.Context) - CDeclAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) CDeclAttr(S.Context, AL)); return; case ParsedAttr::AT_Pascal: - D->addAttr(::new (S.Context) - PascalAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) PascalAttr(S.Context, AL)); return; case ParsedAttr::AT_SwiftCall: - D->addAttr(::new (S.Context) - SwiftCallAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) SwiftCallAttr(S.Context, AL)); return; case ParsedAttr::AT_VectorCall: - D->addAttr(::new (S.Context) - VectorCallAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) VectorCallAttr(S.Context, AL)); return; case ParsedAttr::AT_MSABI: - D->addAttr(::new (S.Context) - MSABIAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) MSABIAttr(S.Context, AL)); return; case ParsedAttr::AT_SysVABI: - D->addAttr(::new (S.Context) - SysVABIAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) SysVABIAttr(S.Context, AL)); return; case ParsedAttr::AT_RegCall: - D->addAttr(::new (S.Context) RegCallAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) RegCallAttr(S.Context, AL)); return; case ParsedAttr::AT_Pcs: { PcsAttr::PCSType PCS; @@ -4490,28 +4320,20 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) { llvm_unreachable("unexpected calling convention in pcs attribute"); } - D->addAttr(::new (S.Context) - PcsAttr(AL.getRange(), S.Context, PCS, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) PcsAttr(S.Context, AL, PCS)); return; } case ParsedAttr::AT_AArch64VectorPcs: - D->addAttr(::new(S.Context) - AArch64VectorPcsAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AArch64VectorPcsAttr(S.Context, AL)); return; case ParsedAttr::AT_IntelOclBicc: - D->addAttr(::new (S.Context) - IntelOclBiccAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) IntelOclBiccAttr(S.Context, AL)); return; case ParsedAttr::AT_PreserveMost: - D->addAttr(::new (S.Context) PreserveMostAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) PreserveMostAttr(S.Context, AL)); return; case ParsedAttr::AT_PreserveAll: - D->addAttr(::new (S.Context) PreserveAllAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) PreserveAllAttr(S.Context, AL)); return; default: llvm_unreachable("unexpected attribute kind"); @@ -4533,9 +4355,71 @@ static void handleSuppressAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // clang-tidy knows about available rules. DiagnosticIdentifiers.push_back(RuleName); } - D->addAttr(::new (S.Context) SuppressAttr( - AL.getRange(), S.Context, DiagnosticIdentifiers.data(), - DiagnosticIdentifiers.size(), AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + SuppressAttr(S.Context, AL, DiagnosticIdentifiers.data(), + DiagnosticIdentifiers.size())); +} + +static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + TypeSourceInfo *DerefTypeLoc = nullptr; + QualType ParmType; + if (AL.hasParsedType()) { + ParmType = S.GetTypeFromParser(AL.getTypeArg(), &DerefTypeLoc); + + unsigned SelectIdx = ~0U; + if (ParmType->isVoidType()) + SelectIdx = 0; + else if (ParmType->isReferenceType()) + SelectIdx = 1; + else if (ParmType->isArrayType()) + SelectIdx = 2; + + if (SelectIdx != ~0U) { + S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument) + << SelectIdx << AL; + return; + } + } + + // To check if earlier decl attributes do not conflict the newly parsed ones + // we always add (and check) the attribute to the cannonical decl. + D = D->getCanonicalDecl(); + if (AL.getKind() == ParsedAttr::AT_Owner) { + if (checkAttrMutualExclusion<PointerAttr>(S, D, AL)) + return; + if (const auto *OAttr = D->getAttr<OwnerAttr>()) { + const Type *ExistingDerefType = OAttr->getDerefTypeLoc() + ? OAttr->getDerefType().getTypePtr() + : nullptr; + if (ExistingDerefType != ParmType.getTypePtrOrNull()) { + S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) + << AL << OAttr; + S.Diag(OAttr->getLocation(), diag::note_conflicting_attribute); + } + return; + } + for (Decl *Redecl : D->redecls()) { + Redecl->addAttr(::new (S.Context) OwnerAttr(S.Context, AL, DerefTypeLoc)); + } + } else { + if (checkAttrMutualExclusion<OwnerAttr>(S, D, AL)) + return; + if (const auto *PAttr = D->getAttr<PointerAttr>()) { + const Type *ExistingDerefType = PAttr->getDerefTypeLoc() + ? PAttr->getDerefType().getTypePtr() + : nullptr; + if (ExistingDerefType != ParmType.getTypePtrOrNull()) { + S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) + << AL << PAttr; + S.Diag(PAttr->getLocation(), diag::note_conflicting_attribute); + } + return; + } + for (Decl *Redecl : D->redecls()) { + Redecl->addAttr(::new (S.Context) + PointerAttr(S.Context, AL, DerefTypeLoc)); + } + } } bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, @@ -4668,6 +4552,11 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, CC = CC_C; break; + case TargetInfo::CCCR_Error: + Diag(Attrs.getLoc(), diag::error_cconv_unsupported) + << Attrs << (int)CallingConventionIgnoredReason::ForThisTarget; + break; + case TargetInfo::CCCR_Warning: { Diag(Attrs.getLoc(), diag::warn_cconv_unsupported) << Attrs << (int)CallingConventionIgnoredReason::ForThisTarget; @@ -4721,21 +4610,15 @@ static bool isValidSwiftErrorResultType(QualType Ty) { return isValidSwiftContextType(Ty); } -static void handleParameterABIAttr(Sema &S, Decl *D, const ParsedAttr &Attrs, - ParameterABI Abi) { - S.AddParameterABIAttr(Attrs.getRange(), D, Abi, - Attrs.getAttributeSpellingListIndex()); -} - -void Sema::AddParameterABIAttr(SourceRange range, Decl *D, ParameterABI abi, - unsigned spellingIndex) { +void Sema::AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI, + ParameterABI abi) { QualType type = cast<ParmVarDecl>(D)->getType(); if (auto existingAttr = D->getAttr<ParameterABIAttr>()) { if (existingAttr->getABI() != abi) { - Diag(range.getBegin(), diag::err_attributes_are_not_compatible) - << getParameterABISpelling(abi) << existingAttr; + Diag(CI.getLoc(), diag::err_attributes_are_not_compatible) + << getParameterABISpelling(abi) << existingAttr; Diag(existingAttr->getLocation(), diag::note_conflicting_attribute); return; } @@ -4747,32 +4630,26 @@ void Sema::AddParameterABIAttr(SourceRange range, Decl *D, ParameterABI abi, case ParameterABI::SwiftContext: if (!isValidSwiftContextType(type)) { - Diag(range.getBegin(), diag::err_swift_abi_parameter_wrong_type) - << getParameterABISpelling(abi) - << /*pointer to pointer */ 0 << type; + Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type) + << getParameterABISpelling(abi) << /*pointer to pointer */ 0 << type; } - D->addAttr(::new (Context) - SwiftContextAttr(range, Context, spellingIndex)); + D->addAttr(::new (Context) SwiftContextAttr(Context, CI)); return; case ParameterABI::SwiftErrorResult: if (!isValidSwiftErrorResultType(type)) { - Diag(range.getBegin(), diag::err_swift_abi_parameter_wrong_type) - << getParameterABISpelling(abi) - << /*pointer to pointer */ 1 << type; + Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type) + << getParameterABISpelling(abi) << /*pointer to pointer */ 1 << type; } - D->addAttr(::new (Context) - SwiftErrorResultAttr(range, Context, spellingIndex)); + D->addAttr(::new (Context) SwiftErrorResultAttr(Context, CI)); return; case ParameterABI::SwiftIndirectResult: if (!isValidSwiftIndirectResultType(type)) { - Diag(range.getBegin(), diag::err_swift_abi_parameter_wrong_type) - << getParameterABISpelling(abi) - << /*pointer*/ 0 << type; + Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type) + << getParameterABISpelling(abi) << /*pointer*/ 0 << type; } - D->addAttr(::new (Context) - SwiftIndirectResultAttr(range, Context, spellingIndex)); + D->addAttr(::new (Context) SwiftIndirectResultAttr(Context, CI)); return; } llvm_unreachable("bad parameter ABI attribute"); @@ -4855,10 +4732,9 @@ static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E, return ValArg.getAs<Expr>(); } -void Sema::AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads, - Expr *MinBlocks, unsigned SpellingListIndex) { - CUDALaunchBoundsAttr TmpAttr(AttrRange, Context, MaxThreads, MinBlocks, - SpellingListIndex); +void Sema::AddLaunchBoundsAttr(Decl *D, const AttributeCommonInfo &CI, + Expr *MaxThreads, Expr *MinBlocks) { + CUDALaunchBoundsAttr TmpAttr(Context, CI, MaxThreads, MinBlocks); MaxThreads = makeLaunchBoundsArgExpr(*this, MaxThreads, TmpAttr, 0); if (MaxThreads == nullptr) return; @@ -4869,8 +4745,8 @@ void Sema::AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads, return; } - D->addAttr(::new (Context) CUDALaunchBoundsAttr( - AttrRange, Context, MaxThreads, MinBlocks, SpellingListIndex)); + D->addAttr(::new (Context) + CUDALaunchBoundsAttr(Context, CI, MaxThreads, MinBlocks)); } static void handleLaunchBoundsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -4878,9 +4754,8 @@ static void handleLaunchBoundsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { !checkAttributeAtMostNumArgs(S, AL, 2)) return; - S.AddLaunchBoundsAttr(AL.getRange(), D, AL.getArgAsExpr(0), - AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr, - AL.getAttributeSpellingListIndex()); + S.AddLaunchBoundsAttr(D, AL, AL.getArgAsExpr(0), + AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr); } static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, @@ -4901,7 +4776,7 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, TypeTagIdx)) return; - bool IsPointer = AL.getName()->getName() == "pointer_with_type_tag"; + bool IsPointer = AL.getAttrName()->getName() == "pointer_with_type_tag"; if (IsPointer) { // Ensure that buffer has a pointer type. unsigned ArgumentIdxAST = ArgumentIdx.getASTIndex(); @@ -4911,8 +4786,8 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, } D->addAttr(::new (S.Context) ArgumentWithTypeTagAttr( - AL.getRange(), S.Context, AL.getArgAsIdent(0)->Ident, ArgumentIdx, - TypeTagIdx, IsPointer, AL.getAttributeSpellingListIndex())); + S.Context, AL, AL.getArgAsIdent(0)->Ident, ArgumentIdx, TypeTagIdx, + IsPointer)); } static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D, @@ -4937,12 +4812,9 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D, S.GetTypeFromParser(AL.getMatchingCType(), &MatchingCTypeLoc); assert(MatchingCTypeLoc && "no type source info for attribute argument"); - D->addAttr(::new (S.Context) - TypeTagForDatatypeAttr(AL.getRange(), S.Context, PointerKind, - MatchingCTypeLoc, - AL.getLayoutCompatible(), - AL.getMustBeNull(), - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) TypeTagForDatatypeAttr( + S.Context, AL, PointerKind, MatchingCTypeLoc, AL.getLayoutCompatible(), + AL.getMustBeNull())); } static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -4954,9 +4826,8 @@ static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; // ArgCount isn't a parameter index [0;n), it's a count [1;n] - D->addAttr(::new (S.Context) XRayLogArgsAttr( - AL.getRange(), S.Context, ArgCount.getSourceIndex(), - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + XRayLogArgsAttr(S.Context, AL, ArgCount.getSourceIndex())); } //===----------------------------------------------------------------------===// @@ -4983,20 +4854,20 @@ static bool isValidSubjectOfOSAttribute(QualType QT) { return !PT.isNull() && PT->getAsCXXRecordDecl() != nullptr; } -void Sema::AddXConsumedAttr(Decl *D, SourceRange SR, unsigned SpellingIndex, +void Sema::AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI, RetainOwnershipKind K, bool IsTemplateInstantiation) { ValueDecl *VD = cast<ValueDecl>(D); switch (K) { case RetainOwnershipKind::OS: handleSimpleAttributeOrDiagnose<OSConsumedAttr>( - *this, VD, SR, SpellingIndex, isValidSubjectOfOSAttribute(VD->getType()), + *this, VD, CI, isValidSubjectOfOSAttribute(VD->getType()), diag::warn_ns_attribute_wrong_parameter_type, - /*ExtraArgs=*/SR, "os_consumed", /*pointers*/ 1); + /*ExtraArgs=*/CI.getRange(), "os_consumed", /*pointers*/ 1); return; case RetainOwnershipKind::NS: handleSimpleAttributeOrDiagnose<NSConsumedAttr>( - *this, VD, SR, SpellingIndex, isValidSubjectOfNSAttribute(VD->getType()), + *this, VD, CI, isValidSubjectOfNSAttribute(VD->getType()), // These attributes are normally just advisory, but in ARC, ns_consumed // is significant. Allow non-dependent code to contain inappropriate @@ -5005,14 +4876,13 @@ void Sema::AddXConsumedAttr(Decl *D, SourceRange SR, unsigned SpellingIndex, ((IsTemplateInstantiation && getLangOpts().ObjCAutoRefCount) ? diag::err_ns_attribute_wrong_parameter_type : diag::warn_ns_attribute_wrong_parameter_type), - /*ExtraArgs=*/SR, "ns_consumed", /*objc pointers*/ 0); + /*ExtraArgs=*/CI.getRange(), "ns_consumed", /*objc pointers*/ 0); return; case RetainOwnershipKind::CF: handleSimpleAttributeOrDiagnose<CFConsumedAttr>( - *this, VD, SR, SpellingIndex, - isValidSubjectOfCFAttribute(VD->getType()), + *this, VD, CI, isValidSubjectOfCFAttribute(VD->getType()), diag::warn_ns_attribute_wrong_parameter_type, - /*ExtraArgs=*/SR, "cf_consumed", /*pointers*/1); + /*ExtraArgs=*/CI.getRange(), "cf_consumed", /*pointers*/ 1); return; } } @@ -5215,8 +5085,7 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, return; } - D->addAttr(::new (S.Context) ObjCReturnsInnerPointerAttr( - Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ObjCReturnsInnerPointerAttr(S.Context, Attrs)); } static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, @@ -5236,8 +5105,7 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, return; } - D->addAttr(::new (S.Context) ObjCRequiresSuperAttr( - Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(S.Context, Attrs)); } static void handleObjCBridgeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -5263,9 +5131,7 @@ static void handleObjCBridgeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } - D->addAttr(::new (S.Context) - ObjCBridgeAttr(AL.getRange(), S.Context, Parm->Ident, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ObjCBridgeAttr(S.Context, AL, Parm->Ident)); } static void handleObjCBridgeMutableAttr(Sema &S, Decl *D, @@ -5278,8 +5144,7 @@ static void handleObjCBridgeMutableAttr(Sema &S, Decl *D, } D->addAttr(::new (S.Context) - ObjCBridgeMutableAttr(AL.getRange(), S.Context, Parm->Ident, - AL.getAttributeSpellingListIndex())); + ObjCBridgeMutableAttr(S.Context, AL, Parm->Ident)); } static void handleObjCBridgeRelatedAttr(Sema &S, Decl *D, @@ -5294,10 +5159,8 @@ static void handleObjCBridgeRelatedAttr(Sema &S, Decl *D, AL.getArgAsIdent(1) ? AL.getArgAsIdent(1)->Ident : nullptr; IdentifierInfo *InstanceMethod = AL.getArgAsIdent(2) ? AL.getArgAsIdent(2)->Ident : nullptr; - D->addAttr(::new (S.Context) - ObjCBridgeRelatedAttr(AL.getRange(), S.Context, RelatedClass, - ClassMethod, InstanceMethod, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ObjCBridgeRelatedAttr( + S.Context, AL, RelatedClass, ClassMethod, InstanceMethod)); } static void handleObjCDesignatedInitializer(Sema &S, Decl *D, @@ -5323,9 +5186,7 @@ static void handleObjCDesignatedInitializer(Sema &S, Decl *D, return; IFace->setHasDesignatedInitializers(); - D->addAttr(::new (S.Context) - ObjCDesignatedInitializerAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ObjCDesignatedInitializerAttr(S.Context, AL)); } static void handleObjCRuntimeName(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -5333,9 +5194,7 @@ static void handleObjCRuntimeName(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.checkStringLiteralArgumentAttr(AL, 0, MetaDataName)) return; D->addAttr(::new (S.Context) - ObjCRuntimeNameAttr(AL.getRange(), S.Context, - MetaDataName, - AL.getAttributeSpellingListIndex())); + ObjCRuntimeNameAttr(S.Context, AL, MetaDataName)); } // When a user wants to use objc_boxable with a union or struct @@ -5352,9 +5211,8 @@ static void handleObjCBoxable(Sema &S, Decl *D, const ParsedAttr &AL) { } if (RD) { - ObjCBoxableAttr *BoxableAttr = ::new (S.Context) - ObjCBoxableAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex()); + ObjCBoxableAttr *BoxableAttr = + ::new (S.Context) ObjCBoxableAttr(S.Context, AL); RD->addAttr(BoxableAttr); if (notify) { // we need to notify ASTReader/ASTWriter about @@ -5408,26 +5266,24 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, break; } - D->addAttr(::new (S.Context) - ObjCPreciseLifetimeAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ObjCPreciseLifetimeAttr(S.Context, AL)); } //===----------------------------------------------------------------------===// // Microsoft specific attribute handlers. //===----------------------------------------------------------------------===// -UuidAttr *Sema::mergeUuidAttr(Decl *D, SourceRange Range, - unsigned AttrSpellingListIndex, StringRef Uuid) { +UuidAttr *Sema::mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI, + StringRef Uuid) { if (const auto *UA = D->getAttr<UuidAttr>()) { if (UA->getGuid().equals_lower(Uuid)) return nullptr; Diag(UA->getLocation(), diag::err_mismatched_uuid); - Diag(Range.getBegin(), diag::note_previous_uuid); + Diag(CI.getLoc(), diag::note_previous_uuid); D->dropAttr<UuidAttr>(); } - return ::new (Context) UuidAttr(Range, Context, Uuid, AttrSpellingListIndex); + return ::new (Context) UuidAttr(Context, CI, Uuid); } static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -5474,8 +5330,7 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (AL.isMicrosoftAttribute()) // Check for [uuid(...)] spelling. S.Diag(AL.getLoc(), diag::warn_atl_uuid_deprecated); - UuidAttr *UA = S.mergeUuidAttr(D, AL.getRange(), - AL.getAttributeSpellingListIndex(), StrRef); + UuidAttr *UA = S.mergeUuidAttr(D, AL, StrRef); if (UA) D->addAttr(UA); } @@ -5487,8 +5342,7 @@ static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } MSInheritanceAttr *IA = S.mergeMSInheritanceAttr( - D, AL.getRange(), /*BestCase=*/true, - AL.getAttributeSpellingListIndex(), + D, AL, /*BestCase=*/true, (MSInheritanceAttr::Spelling)AL.getSemanticSpelling()); if (IA) { D->addAttr(IA); @@ -5510,8 +5364,7 @@ static void handleDeclspecThreadAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.Diag(AL.getLoc(), diag::err_thread_non_global) << "__declspec(thread)"; return; } - D->addAttr(::new (S.Context) ThreadAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ThreadAttr(S.Context, AL)); } static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -5542,8 +5395,7 @@ static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end()); D->addAttr(::new (S.Context) - AbiTagAttr(AL.getRange(), S.Context, Tags.data(), Tags.size(), - AL.getAttributeSpellingListIndex())); + AbiTagAttr(S.Context, AL, Tags.data(), Tags.size())); } static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -5568,9 +5420,7 @@ static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - unsigned Index = AL.getAttributeSpellingListIndex(); - D->addAttr(::new (S.Context) - ARMInterruptAttr(AL.getLoc(), S.Context, Kind, Index)); + D->addAttr(::new (S.Context) ARMInterruptAttr(S.Context, AL, Kind)); } static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -5621,9 +5471,7 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) - MSP430InterruptAttr(AL.getLoc(), S.Context, Num, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) MSP430InterruptAttr(S.Context, AL, Num)); D->addAttr(UsedAttr::CreateImplicit(S.Context)); } @@ -5679,8 +5527,7 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) MipsInterruptAttr( - AL.getLoc(), S.Context, Kind, AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) MipsInterruptAttr(S.Context, AL, Kind)); } static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -5743,8 +5590,7 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { << 3 << S.Context.getIntTypeForBitwidth(TypeSize, /*Signed=*/false); return; } - D->addAttr(::new (S.Context) AnyX86InterruptAttr( - AL.getLoc(), S.Context, AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AnyX86InterruptAttr(S.Context, AL)); D->addAttr(UsedAttr::CreateImplicit(S.Context)); } @@ -5792,9 +5638,8 @@ static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) return; - FD->addAttr(::new (S.Context) WebAssemblyImportModuleAttr( - AL.getRange(), S.Context, Str, - AL.getAttributeSpellingListIndex())); + FD->addAttr(::new (S.Context) + WebAssemblyImportModuleAttr(S.Context, AL, Str)); } static void handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -5815,9 +5660,7 @@ static void handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr & if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) return; - FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr( - AL.getRange(), S.Context, Str, - AL.getAttributeSpellingListIndex())); + FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr(S.Context, AL, Str)); } static void handleRISCVInterruptAttr(Sema &S, Decl *D, @@ -5875,8 +5718,7 @@ static void handleRISCVInterruptAttr(Sema &S, Decl *D, return; } - D->addAttr(::new (S.Context) RISCVInterruptAttr( - AL.getLoc(), S.Context, Kind, AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) RISCVInterruptAttr(S.Context, AL, Kind)); } static void handleInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -5936,17 +5778,16 @@ checkAMDGPUFlatWorkGroupSizeArguments(Sema &S, Expr *MinExpr, Expr *MaxExpr, return false; } -void Sema::addAMDGPUFlatWorkGroupSizeAttr(SourceRange AttrRange, Decl *D, - Expr *MinExpr, Expr *MaxExpr, - unsigned SpellingListIndex) { - AMDGPUFlatWorkGroupSizeAttr TmpAttr(AttrRange, Context, MinExpr, MaxExpr, - SpellingListIndex); +void Sema::addAMDGPUFlatWorkGroupSizeAttr(Decl *D, + const AttributeCommonInfo &CI, + Expr *MinExpr, Expr *MaxExpr) { + AMDGPUFlatWorkGroupSizeAttr TmpAttr(Context, CI, MinExpr, MaxExpr); if (checkAMDGPUFlatWorkGroupSizeArguments(*this, MinExpr, MaxExpr, TmpAttr)) return; - D->addAttr(::new (Context) AMDGPUFlatWorkGroupSizeAttr( - AttrRange, Context, MinExpr, MaxExpr, SpellingListIndex)); + D->addAttr(::new (Context) + AMDGPUFlatWorkGroupSizeAttr(Context, CI, MinExpr, MaxExpr)); } static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D, @@ -5954,8 +5795,7 @@ static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D, Expr *MinExpr = AL.getArgAsExpr(0); Expr *MaxExpr = AL.getArgAsExpr(1); - S.addAMDGPUFlatWorkGroupSizeAttr(AL.getRange(), D, MinExpr, MaxExpr, - AL.getAttributeSpellingListIndex()); + S.addAMDGPUFlatWorkGroupSizeAttr(D, AL, MinExpr, MaxExpr); } static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr, @@ -5992,17 +5832,15 @@ static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr, return false; } -void Sema::addAMDGPUWavesPerEUAttr(SourceRange AttrRange, Decl *D, - Expr *MinExpr, Expr *MaxExpr, - unsigned SpellingListIndex) { - AMDGPUWavesPerEUAttr TmpAttr(AttrRange, Context, MinExpr, MaxExpr, - SpellingListIndex); +void Sema::addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI, + Expr *MinExpr, Expr *MaxExpr) { + AMDGPUWavesPerEUAttr TmpAttr(Context, CI, MinExpr, MaxExpr); if (checkAMDGPUWavesPerEUArguments(*this, MinExpr, MaxExpr, TmpAttr)) return; - D->addAttr(::new (Context) AMDGPUWavesPerEUAttr(AttrRange, Context, MinExpr, - MaxExpr, SpellingListIndex)); + D->addAttr(::new (Context) + AMDGPUWavesPerEUAttr(Context, CI, MinExpr, MaxExpr)); } static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -6013,8 +5851,7 @@ static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) { Expr *MinExpr = AL.getArgAsExpr(0); Expr *MaxExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr; - S.addAMDGPUWavesPerEUAttr(AL.getRange(), D, MinExpr, MaxExpr, - AL.getAttributeSpellingListIndex()); + S.addAMDGPUWavesPerEUAttr(D, AL, MinExpr, MaxExpr); } static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -6023,9 +5860,7 @@ static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!checkUInt32Argument(S, AL, NumSGPRExpr, NumSGPR)) return; - D->addAttr(::new (S.Context) - AMDGPUNumSGPRAttr(AL.getLoc(), S.Context, NumSGPR, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AMDGPUNumSGPRAttr(S.Context, AL, NumSGPR)); } static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -6034,9 +5869,7 @@ static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!checkUInt32Argument(S, AL, NumVGPRExpr, NumVGPR)) return; - D->addAttr(::new (S.Context) - AMDGPUNumVGPRAttr(AL.getLoc(), S.Context, NumVGPR, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AMDGPUNumVGPRAttr(S.Context, AL, NumVGPR)); } static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D, @@ -6059,9 +5892,7 @@ static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D, return; } - D->addAttr(::new (S.Context) - X86ForceAlignArgPointerAttr(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(S.Context, AL)); } static void handleLayoutVersion(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -6082,26 +5913,24 @@ static void handleLayoutVersion(Sema &S, Decl *D, const ParsedAttr &AL) { // have to multiply by 100 now. Version *= 100; - D->addAttr(::new (S.Context) - LayoutVersionAttr(AL.getRange(), S.Context, Version, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) LayoutVersionAttr(S.Context, AL, Version)); } -DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range, - unsigned AttrSpellingListIndex) { +DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, + const AttributeCommonInfo &CI) { if (D->hasAttr<DLLExportAttr>()) { - Diag(Range.getBegin(), diag::warn_attribute_ignored) << "'dllimport'"; + Diag(CI.getLoc(), diag::warn_attribute_ignored) << "'dllimport'"; return nullptr; } if (D->hasAttr<DLLImportAttr>()) return nullptr; - return ::new (Context) DLLImportAttr(Range, Context, AttrSpellingListIndex); + return ::new (Context) DLLImportAttr(Context, CI); } -DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range, - unsigned AttrSpellingListIndex) { +DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, + const AttributeCommonInfo &CI) { if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) { Diag(Import->getLocation(), diag::warn_attribute_ignored) << Import; D->dropAttr<DLLImportAttr>(); @@ -6110,7 +5939,7 @@ DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range, if (D->hasAttr<DLLExportAttr>()) return nullptr; - return ::new (Context) DLLExportAttr(Range, Context, AttrSpellingListIndex); + return ::new (Context) DLLExportAttr(Context, CI); } static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) { @@ -6138,48 +5967,46 @@ static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) { } } - unsigned Index = A.getAttributeSpellingListIndex(); Attr *NewAttr = A.getKind() == ParsedAttr::AT_DLLExport - ? (Attr *)S.mergeDLLExportAttr(D, A.getRange(), Index) - : (Attr *)S.mergeDLLImportAttr(D, A.getRange(), Index); + ? (Attr *)S.mergeDLLExportAttr(D, A) + : (Attr *)S.mergeDLLImportAttr(D, A); if (NewAttr) D->addAttr(NewAttr); } MSInheritanceAttr * -Sema::mergeMSInheritanceAttr(Decl *D, SourceRange Range, bool BestCase, - unsigned AttrSpellingListIndex, +Sema::mergeMSInheritanceAttr(Decl *D, const AttributeCommonInfo &CI, + bool BestCase, MSInheritanceAttr::Spelling SemanticSpelling) { if (MSInheritanceAttr *IA = D->getAttr<MSInheritanceAttr>()) { if (IA->getSemanticSpelling() == SemanticSpelling) return nullptr; Diag(IA->getLocation(), diag::err_mismatched_ms_inheritance) << 1 /*previous declaration*/; - Diag(Range.getBegin(), diag::note_previous_ms_inheritance); + Diag(CI.getLoc(), diag::note_previous_ms_inheritance); D->dropAttr<MSInheritanceAttr>(); } auto *RD = cast<CXXRecordDecl>(D); if (RD->hasDefinition()) { - if (checkMSInheritanceAttrOnDefinition(RD, Range, BestCase, + if (checkMSInheritanceAttrOnDefinition(RD, CI.getRange(), BestCase, SemanticSpelling)) { return nullptr; } } else { if (isa<ClassTemplatePartialSpecializationDecl>(RD)) { - Diag(Range.getBegin(), diag::warn_ignored_ms_inheritance) + Diag(CI.getLoc(), diag::warn_ignored_ms_inheritance) << 1 /*partial specialization*/; return nullptr; } if (RD->getDescribedClassTemplate()) { - Diag(Range.getBegin(), diag::warn_ignored_ms_inheritance) + Diag(CI.getLoc(), diag::warn_ignored_ms_inheritance) << 0 /*primary template*/; return nullptr; } } - return ::new (Context) - MSInheritanceAttr(Range, Context, BestCase, AttrSpellingListIndex); + return ::new (Context) MSInheritanceAttr(Context, CI, BestCase); } static void handleCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -6202,8 +6029,7 @@ static void handleCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!N.equals_lower("mutex") && !N.equals_lower("role")) S.Diag(LiteralLoc, diag::warn_invalid_capability_name) << N; - D->addAttr(::new (S.Context) CapabilityAttr(AL.getRange(), S.Context, N, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) CapabilityAttr(S.Context, AL, N)); } static void handleAssertCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -6211,9 +6037,8 @@ static void handleAssertCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!checkLockFunAttrCommon(S, D, AL, Args)) return; - D->addAttr(::new (S.Context) AssertCapabilityAttr(AL.getRange(), S.Context, - Args.data(), Args.size(), - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + AssertCapabilityAttr(S.Context, AL, Args.data(), Args.size())); } static void handleAcquireCapabilityAttr(Sema &S, Decl *D, @@ -6222,10 +6047,8 @@ static void handleAcquireCapabilityAttr(Sema &S, Decl *D, if (!checkLockFunAttrCommon(S, D, AL, Args)) return; - D->addAttr(::new (S.Context) AcquireCapabilityAttr(AL.getRange(), - S.Context, - Args.data(), Args.size(), - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AcquireCapabilityAttr(S.Context, AL, Args.data(), + Args.size())); } static void handleTryAcquireCapabilityAttr(Sema &S, Decl *D, @@ -6234,12 +6057,8 @@ static void handleTryAcquireCapabilityAttr(Sema &S, Decl *D, if (!checkTryLockFunAttrCommon(S, D, AL, Args)) return; - D->addAttr(::new (S.Context) TryAcquireCapabilityAttr(AL.getRange(), - S.Context, - AL.getArgAsExpr(0), - Args.data(), - Args.size(), - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) TryAcquireCapabilityAttr( + S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size())); } static void handleReleaseCapabilityAttr(Sema &S, Decl *D, @@ -6248,9 +6067,8 @@ static void handleReleaseCapabilityAttr(Sema &S, Decl *D, SmallVector<Expr *, 1> Args; checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 0, true); - D->addAttr(::new (S.Context) ReleaseCapabilityAttr( - AL.getRange(), S.Context, Args.data(), Args.size(), - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ReleaseCapabilityAttr(S.Context, AL, Args.data(), + Args.size())); } static void handleRequiresCapabilityAttr(Sema &S, Decl *D, @@ -6265,8 +6083,7 @@ static void handleRequiresCapabilityAttr(Sema &S, Decl *D, return; RequiresCapabilityAttr *RCA = ::new (S.Context) - RequiresCapabilityAttr(AL.getRange(), S.Context, Args.data(), - Args.size(), AL.getAttributeSpellingListIndex()); + RequiresCapabilityAttr(S.Context, AL, Args.data(), Args.size()); D->addAttr(RCA); } @@ -6298,9 +6115,7 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.getLangOpts().CPlusPlus14 && AL.isCXX11Attribute() && !AL.isGNUScope()) S.Diag(AL.getLoc(), diag::ext_cxx14_attr) << AL; - D->addAttr(::new (S.Context) - DeprecatedAttr(AL.getRange(), S.Context, Str, Replacement, - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) DeprecatedAttr(S.Context, AL, Str, Replacement)); } static bool isGlobalVar(const Decl *D) { @@ -6331,14 +6146,13 @@ static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { Sanitizers.push_back(SanitizerName); } - D->addAttr(::new (S.Context) NoSanitizeAttr( - AL.getRange(), S.Context, Sanitizers.data(), Sanitizers.size(), - AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) NoSanitizeAttr(S.Context, AL, Sanitizers.data(), + Sanitizers.size())); } static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - StringRef AttrName = AL.getName()->getName(); + StringRef AttrName = AL.getAttrName()->getName(); normalizeName(AttrName); StringRef SanitizerName = llvm::StringSwitch<StringRef>(AttrName) .Case("no_address_safety_analysis", "address") @@ -6361,8 +6175,10 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D, if (AL.isC2xAttribute() || AL.isCXX11Attribute()) TranslatedSpellingIndex = 1; - D->addAttr(::new (S.Context) NoSanitizeAttr( - AL.getRange(), S.Context, &SanitizerName, 1, TranslatedSpellingIndex)); + AttributeCommonInfo Info = AL; + Info.setAttributeSpellingListIndex(TranslatedSpellingIndex); + D->addAttr(::new (S.Context) + NoSanitizeAttr(S.Context, Info, &SanitizerName, 1)); } static void handleInternalLinkageAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -6431,7 +6247,7 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (D->getAttr<OpenCLAccessAttr>()->getSemanticSpelling() == AL.getSemanticSpelling()) { S.Diag(AL.getLoc(), diag::warn_duplicate_declspec) - << AL.getName()->getName() << AL.getRange(); + << AL.getAttrName()->getName() << AL.getRange(); } else { S.Diag(AL.getLoc(), diag::err_opencl_multiple_access_qualifiers) << D->getSourceRange(); @@ -6447,7 +6263,7 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // qualifier is a compilation error. if (const auto *PDecl = dyn_cast<ParmVarDecl>(D)) { const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr(); - if (AL.getName()->getName().find("read_write") != StringRef::npos) { + if (AL.getAttrName()->getName().find("read_write") != StringRef::npos) { if ((!S.getLangOpts().OpenCLCPlusPlus && S.getLangOpts().OpenCLVersion < 200) || DeclTy->isPipeType()) { @@ -6459,8 +6275,7 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } - D->addAttr(::new (S.Context) OpenCLAccessAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) OpenCLAccessAttr(S.Context, AL)); } static void handleDestroyAttr(Sema &S, Decl *D, const ParsedAttr &A) { @@ -6479,9 +6294,7 @@ static void handleDestroyAttr(Sema &S, Decl *D, const ParsedAttr &A) { static void handleUninitializedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { assert(cast<VarDecl>(D)->getStorageDuration() == SD_Automatic && "uninitialized is only valid on automatic duration variables"); - unsigned Index = AL.getAttributeSpellingListIndex(); - D->addAttr(::new (S.Context) - UninitializedAttr(AL.getLoc(), S.Context, Index)); + D->addAttr(::new (S.Context) UninitializedAttr(S.Context, AL)); } static bool tryMakeVariablePseudoStrong(Sema &S, VarDecl *VD, @@ -6932,9 +6745,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_CFConsumed: case ParsedAttr::AT_NSConsumed: case ParsedAttr::AT_OSConsumed: - S.AddXConsumedAttr(D, AL.getRange(), AL.getAttributeSpellingListIndex(), - parsedAttrToRetainOwnershipKind(AL), - /*IsTemplateInstantiation=*/false); + S.AddXConsumedAttr(D, AL, parsedAttrToRetainOwnershipKind(AL), + /*IsTemplateInstantiation=*/false); break; case ParsedAttr::AT_NSConsumesSelf: handleSimpleAttribute<NSConsumesSelfAttr>(S, D, AL); @@ -6975,8 +6787,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_VecTypeHint: handleVecTypeHint(S, D, AL); break; - case ParsedAttr::AT_RequireConstantInit: - handleSimpleAttribute<RequireConstantInitAttr>(S, D, AL); + case ParsedAttr::AT_ConstInit: + handleSimpleAttribute<ConstInitAttr>(S, D, AL); break; case ParsedAttr::AT_InitPriority: handleInitPriorityAttr(S, D, AL); @@ -7116,6 +6928,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, // Interacts with -fstack-protector options. handleSimpleAttribute<NoStackProtectorAttr>(S, D, AL); break; + case ParsedAttr::AT_CFICanonicalJumpTable: + handleSimpleAttribute<CFICanonicalJumpTableAttr>(S, D, AL); + break; case ParsedAttr::AT_StdCall: case ParsedAttr::AT_CDecl: case ParsedAttr::AT_FastCall: @@ -7136,6 +6951,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_Suppress: handleSuppressAttr(S, D, AL); break; + case ParsedAttr::AT_Owner: + case ParsedAttr::AT_Pointer: + handleLifetimeCategoryAttr(S, D, AL); + break; case ParsedAttr::AT_OpenCLKernel: handleSimpleAttribute<OpenCLKernelAttr>(S, D, AL); break; @@ -7146,13 +6965,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleOpenCLNoSVMAttr(S, D, AL); break; case ParsedAttr::AT_SwiftContext: - handleParameterABIAttr(S, D, AL, ParameterABI::SwiftContext); + S.AddParameterABIAttr(D, AL, ParameterABI::SwiftContext); break; case ParsedAttr::AT_SwiftErrorResult: - handleParameterABIAttr(S, D, AL, ParameterABI::SwiftErrorResult); + S.AddParameterABIAttr(D, AL, ParameterABI::SwiftErrorResult); break; case ParsedAttr::AT_SwiftIndirectResult: - handleParameterABIAttr(S, D, AL, ParameterABI::SwiftIndirectResult); + S.AddParameterABIAttr(D, AL, ParameterABI::SwiftIndirectResult); break; case ParsedAttr::AT_InternalLinkage: handleInternalLinkageAttr(S, D, AL); @@ -7526,9 +7345,10 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) { if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...)) IdentifierInfo *NDId = ND->getIdentifier(); NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias(), W.getLocation()); - NewD->addAttr(AliasAttr::CreateImplicit(Context, NDId->getName(), - W.getLocation())); - NewD->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation())); + NewD->addAttr( + AliasAttr::CreateImplicit(Context, NDId->getName(), W.getLocation())); + NewD->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation(), + AttributeCommonInfo::AS_Pragma)); WeakTopLevelDecl.push_back(NewD); // FIXME: "hideous" code from Sema::LazilyCreateBuiltin // to insert Decl at TU scope, sorry. @@ -7539,7 +7359,8 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) { PushOnScopeChains(NewD, S); CurContext = SavedContext; } else { // just add weak to existing - ND->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation())); + ND->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation(), + AttributeCommonInfo::AS_Pragma)); } } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 9a6385f28319..ff90b9548e29 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -24,6 +24,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" +#include "clang/Basic/AttributeCommonInfo.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/LiteralSupport.h" @@ -774,6 +775,13 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, return nullptr; } + // C++2a [dcl.struct.bind]p1: + // A cv that includes volatile is deprecated + if ((DS.getTypeQualifiers() & DeclSpec::TQ_volatile) && + getLangOpts().CPlusPlus2a) + Diag(DS.getVolatileSpecLoc(), + diag::warn_deprecated_volatile_structured_binding); + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType R = TInfo->getType(); @@ -1030,8 +1038,10 @@ static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T, TemplateArgumentListInfo Args(Loc, Loc); Args.addArgument(getTrivialTypeTemplateArgument(S, Loc, T)); - // If there's no tuple_size specialization, it's not tuple-like. - if (lookupStdTypeTraitMember(S, R, Loc, "tuple_size", Args, /*DiagID*/0)) + // If there's no tuple_size specialization or the lookup of 'value' is empty, + // it's not tuple-like. + if (lookupStdTypeTraitMember(S, R, Loc, "tuple_size", Args, /*DiagID*/ 0) || + R.empty()) return IsTupleLike::NotTupleLike; // If we get this far, we've committed to the tuple interpretation, but @@ -1048,11 +1058,6 @@ static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T, } } Diagnoser(R, Args); - if (R.empty()) { - Diagnoser.diagnoseNotICE(S, Loc, SourceRange()); - return IsTupleLike::Error; - } - ExprResult E = S.BuildDeclarationNameExpr(CXXScopeSpec(), R, /*NeedsADL*/false); if (E.isInvalid()) @@ -1228,7 +1233,8 @@ static bool checkTupleLikeDecomposition(Sema &S, if (E.isInvalid()) return true; RefVD->setInit(E.get()); - RefVD->checkInitIsICE(); + if (!E.get()->isValueDependent()) + RefVD->checkInitIsICE(); E = S.BuildDeclarationNameExpr(CXXScopeSpec(), DeclarationNameInfo(B->getDeclName(), Loc), @@ -1569,11 +1575,64 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { } } +/// Check that the given type is a literal type. Issue a diagnostic if not, +/// if Kind is Diagnose. +/// \return \c true if a problem has been found (and optionally diagnosed). +template <typename... Ts> +static bool CheckLiteralType(Sema &SemaRef, Sema::CheckConstexprKind Kind, + SourceLocation Loc, QualType T, unsigned DiagID, + Ts &&...DiagArgs) { + if (T->isDependentType()) + return false; + + switch (Kind) { + case Sema::CheckConstexprKind::Diagnose: + return SemaRef.RequireLiteralType(Loc, T, DiagID, + std::forward<Ts>(DiagArgs)...); + + case Sema::CheckConstexprKind::CheckValid: + return !T->isLiteralType(SemaRef.Context); + } + + llvm_unreachable("unknown CheckConstexprKind"); +} + +/// Determine whether a destructor cannot be constexpr due to +static bool CheckConstexprDestructorSubobjects(Sema &SemaRef, + const CXXDestructorDecl *DD, + Sema::CheckConstexprKind Kind) { + auto Check = [&](SourceLocation Loc, QualType T, const FieldDecl *FD) { + const CXXRecordDecl *RD = + T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); + if (!RD || RD->hasConstexprDestructor()) + return true; + + if (Kind == Sema::CheckConstexprKind::Diagnose) { + SemaRef.Diag(DD->getLocation(), diag::err_constexpr_dtor_subobject) + << DD->getConstexprKind() << !FD + << (FD ? FD->getDeclName() : DeclarationName()) << T; + SemaRef.Diag(Loc, diag::note_constexpr_dtor_subobject) + << !FD << (FD ? FD->getDeclName() : DeclarationName()) << T; + } + return false; + }; + + const CXXRecordDecl *RD = DD->getParent(); + for (const CXXBaseSpecifier &B : RD->bases()) + if (!Check(B.getBaseTypeLoc(), B.getType(), nullptr)) + return false; + for (const FieldDecl *FD : RD->fields()) + if (!Check(FD->getLocation(), FD->getType(), FD)) + return false; + 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. static bool CheckConstexprParameterTypes(Sema &SemaRef, - const FunctionDecl *FD) { + const FunctionDecl *FD, + Sema::CheckConstexprKind Kind) { unsigned ArgIndex = 0; const FunctionProtoType *FT = FD->getType()->getAs<FunctionProtoType>(); for (FunctionProtoType::param_type_iterator i = FT->param_type_begin(), @@ -1581,11 +1640,10 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef, i != e; ++i, ++ArgIndex) { const ParmVarDecl *PD = FD->getParamDecl(ArgIndex); SourceLocation ParamLoc = PD->getLocation(); - if (!(*i)->isDependentType() && - SemaRef.RequireLiteralType( - ParamLoc, *i, diag::err_constexpr_non_literal_param, ArgIndex + 1, - PD->getSourceRange(), isa<CXXConstructorDecl>(FD), - FD->isConsteval())) + if (CheckLiteralType(SemaRef, Kind, ParamLoc, *i, + diag::err_constexpr_non_literal_param, ArgIndex + 1, + PD->getSourceRange(), isa<CXXConstructorDecl>(FD), + FD->isConsteval())) return false; } return true; @@ -1605,13 +1663,18 @@ static unsigned getRecordDiagFromTagKind(TagTypeKind Tag) { } } -// CheckConstexprFunctionDecl - Check whether a function declaration satisfies -// the requirements of a constexpr function definition or a constexpr -// constructor definition. If so, return true. If not, produce appropriate -// diagnostics and return false. +static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, + Stmt *Body, + Sema::CheckConstexprKind Kind); + +// Check whether a function declaration satisfies the requirements of a +// constexpr function definition or a constexpr constructor definition. If so, +// return true. If not, produce appropriate diagnostics (unless asked not to by +// Kind) and return false. // // This implements C++11 [dcl.constexpr]p3,4, as amended by DR1360. -bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) { +bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD, + CheckConstexprKind Kind) { const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD); if (MD && MD->isInstance()) { // C++11 [dcl.constexpr]p4: @@ -1619,10 +1682,13 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) { // constraints: // - the class shall not have any virtual base classes; // - // FIXME: This only applies to constructors, not arbitrary member - // functions. + // FIXME: This only applies to constructors and destructors, not arbitrary + // member functions. const CXXRecordDecl *RD = MD->getParent(); if (RD->getNumVBases()) { + if (Kind == CheckConstexprKind::CheckValid) + return false; + Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base) << isa<CXXConstructorDecl>(NewFD) << getRecordDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases(); @@ -1641,8 +1707,12 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) { const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD); if (Method && Method->isVirtual()) { if (getLangOpts().CPlusPlus2a) { - Diag(Method->getLocation(), diag::warn_cxx17_compat_constexpr_virtual); + if (Kind == CheckConstexprKind::Diagnose) + Diag(Method->getLocation(), diag::warn_cxx17_compat_constexpr_virtual); } else { + if (Kind == CheckConstexprKind::CheckValid) + return false; + Method = Method->getCanonicalDecl(); Diag(Method->getLocation(), diag::err_constexpr_virtual); @@ -1660,18 +1730,32 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) { // - its return type shall be a literal type; QualType RT = NewFD->getReturnType(); - if (!RT->isDependentType() && - RequireLiteralType(NewFD->getLocation(), RT, - diag::err_constexpr_non_literal_return, - NewFD->isConsteval())) + if (CheckLiteralType(*this, Kind, NewFD->getLocation(), RT, + diag::err_constexpr_non_literal_return, + NewFD->isConsteval())) return false; } + if (auto *Dtor = dyn_cast<CXXDestructorDecl>(NewFD)) { + // A destructor can be constexpr only if the defaulted destructor could be; + // we don't need to check the members and bases if we already know they all + // have constexpr destructors. + if (!Dtor->getParent()->defaultedDestructorIsConstexpr()) { + if (Kind == CheckConstexprKind::CheckValid) + return false; + if (!CheckConstexprDestructorSubobjects(*this, Dtor, Kind)) + return false; + } + } + // - each of its parameter types shall be a literal type; - if (!CheckConstexprParameterTypes(*this, NewFD)) + if (!CheckConstexprParameterTypes(*this, NewFD, Kind)) return false; - return true; + Stmt *Body = NewFD->getBody(); + assert(Body && + "CheckConstexprFunctionDefinition called on function with no body"); + return CheckConstexprFunctionBody(*this, NewFD, Body, Kind); } /// Check the given declaration statement is legal within a constexpr function @@ -1680,7 +1764,8 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) { /// \return true if the body is OK (maybe only as an extension), false if we /// have diagnosed a problem. static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, - DeclStmt *DS, SourceLocation &Cxx1yLoc) { + DeclStmt *DS, SourceLocation &Cxx1yLoc, + Sema::CheckConstexprKind Kind) { // C++11 [dcl.constexpr]p3 and p4: // The definition of a constexpr function(p3) or constructor(p4) [...] shall // contain only @@ -1704,10 +1789,12 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, const auto *TN = cast<TypedefNameDecl>(DclIt); if (TN->getUnderlyingType()->isVariablyModifiedType()) { // Don't allow variably-modified types in constexpr functions. - TypeLoc TL = TN->getTypeSourceInfo()->getTypeLoc(); - SemaRef.Diag(TL.getBeginLoc(), diag::err_constexpr_vla) - << TL.getSourceRange() << TL.getType() - << isa<CXXConstructorDecl>(Dcl); + if (Kind == Sema::CheckConstexprKind::Diagnose) { + TypeLoc TL = TN->getTypeSourceInfo()->getTypeLoc(); + SemaRef.Diag(TL.getBeginLoc(), diag::err_constexpr_vla) + << TL.getSourceRange() << TL.getType() + << isa<CXXConstructorDecl>(Dcl); + } return false; } continue; @@ -1716,12 +1803,17 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, case Decl::Enum: case Decl::CXXRecord: // C++1y allows types to be defined, not just declared. - if (cast<TagDecl>(DclIt)->isThisDeclarationADefinition()) - SemaRef.Diag(DS->getBeginLoc(), - SemaRef.getLangOpts().CPlusPlus14 - ? diag::warn_cxx11_compat_constexpr_type_definition - : diag::ext_constexpr_type_definition) - << isa<CXXConstructorDecl>(Dcl); + if (cast<TagDecl>(DclIt)->isThisDeclarationADefinition()) { + if (Kind == Sema::CheckConstexprKind::Diagnose) { + SemaRef.Diag(DS->getBeginLoc(), + SemaRef.getLangOpts().CPlusPlus14 + ? diag::warn_cxx11_compat_constexpr_type_definition + : diag::ext_constexpr_type_definition) + << isa<CXXConstructorDecl>(Dcl); + } else if (!SemaRef.getLangOpts().CPlusPlus14) { + return false; + } + } continue; case Decl::EnumConstant: @@ -1735,35 +1827,47 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, case Decl::Decomposition: { // C++1y [dcl.constexpr]p3 allows anything except: // a definition of a variable of non-literal type or of static or - // thread storage duration or for which no initialization is performed. + // thread storage duration or [before C++2a] for which no + // initialization is performed. const auto *VD = cast<VarDecl>(DclIt); if (VD->isThisDeclarationADefinition()) { if (VD->isStaticLocal()) { - SemaRef.Diag(VD->getLocation(), - diag::err_constexpr_local_var_static) - << isa<CXXConstructorDecl>(Dcl) - << (VD->getTLSKind() == VarDecl::TLS_Dynamic); + if (Kind == Sema::CheckConstexprKind::Diagnose) { + SemaRef.Diag(VD->getLocation(), + diag::err_constexpr_local_var_static) + << isa<CXXConstructorDecl>(Dcl) + << (VD->getTLSKind() == VarDecl::TLS_Dynamic); + } return false; } - if (!VD->getType()->isDependentType() && - SemaRef.RequireLiteralType( - VD->getLocation(), VD->getType(), - diag::err_constexpr_local_var_non_literal_type, - isa<CXXConstructorDecl>(Dcl))) + if (CheckLiteralType(SemaRef, Kind, VD->getLocation(), VD->getType(), + diag::err_constexpr_local_var_non_literal_type, + isa<CXXConstructorDecl>(Dcl))) return false; if (!VD->getType()->isDependentType() && !VD->hasInit() && !VD->isCXXForRangeDecl()) { - SemaRef.Diag(VD->getLocation(), - diag::err_constexpr_local_var_no_init) - << isa<CXXConstructorDecl>(Dcl); - return false; + if (Kind == Sema::CheckConstexprKind::Diagnose) { + SemaRef.Diag( + VD->getLocation(), + SemaRef.getLangOpts().CPlusPlus2a + ? diag::warn_cxx17_compat_constexpr_local_var_no_init + : diag::ext_constexpr_local_var_no_init) + << isa<CXXConstructorDecl>(Dcl); + } else if (!SemaRef.getLangOpts().CPlusPlus2a) { + return false; + } + continue; } } - SemaRef.Diag(VD->getLocation(), - SemaRef.getLangOpts().CPlusPlus14 - ? diag::warn_cxx11_compat_constexpr_local_var - : diag::ext_constexpr_local_var) - << isa<CXXConstructorDecl>(Dcl); + if (Kind == Sema::CheckConstexprKind::Diagnose) { + SemaRef.Diag(VD->getLocation(), + SemaRef.getLangOpts().CPlusPlus14 + ? diag::warn_cxx11_compat_constexpr_local_var + : diag::ext_constexpr_local_var) + << isa<CXXConstructorDecl>(Dcl); + } else if (!SemaRef.getLangOpts().CPlusPlus14) { + return false; + } continue; } @@ -1776,8 +1880,10 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, continue; default: - SemaRef.Diag(DS->getBeginLoc(), diag::err_constexpr_body_invalid_stmt) - << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval(); + if (Kind == Sema::CheckConstexprKind::Diagnose) { + SemaRef.Diag(DS->getBeginLoc(), diag::err_constexpr_body_invalid_stmt) + << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval(); + } return false; } } @@ -1792,17 +1898,28 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, /// struct or union nested within the class being checked. /// \param Inits All declarations, including anonymous struct/union members and /// indirect members, for which any initialization was provided. -/// \param Diagnosed Set to true if an error is produced. -static void CheckConstexprCtorInitializer(Sema &SemaRef, +/// \param Diagnosed Whether we've emitted the error message yet. Used to attach +/// multiple notes for different members to the same error. +/// \param Kind Whether we're diagnosing a constructor as written or determining +/// whether the formal requirements are satisfied. +/// \return \c false if we're checking for validity and the constructor does +/// not satisfy the requirements on a constexpr constructor. +static bool CheckConstexprCtorInitializer(Sema &SemaRef, const FunctionDecl *Dcl, FieldDecl *Field, llvm::SmallSet<Decl*, 16> &Inits, - bool &Diagnosed) { + bool &Diagnosed, + Sema::CheckConstexprKind Kind) { + // In C++20 onwards, there's nothing to check for validity. + if (Kind == Sema::CheckConstexprKind::CheckValid && + SemaRef.getLangOpts().CPlusPlus2a) + return true; + if (Field->isInvalidDecl()) - return; + return true; if (Field->isUnnamedBitfield()) - return; + return true; // Anonymous unions with no variant members and empty anonymous structs do not // need to be explicitly initialized. FIXME: Anonymous structs that contain no @@ -1811,22 +1928,33 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef, (Field->getType()->isUnionType() ? !Field->getType()->getAsCXXRecordDecl()->hasVariantMembers() : Field->getType()->getAsCXXRecordDecl()->isEmpty())) - return; + return true; if (!Inits.count(Field)) { - if (!Diagnosed) { - SemaRef.Diag(Dcl->getLocation(), diag::err_constexpr_ctor_missing_init); - Diagnosed = true; + if (Kind == Sema::CheckConstexprKind::Diagnose) { + if (!Diagnosed) { + SemaRef.Diag(Dcl->getLocation(), + SemaRef.getLangOpts().CPlusPlus2a + ? diag::warn_cxx17_compat_constexpr_ctor_missing_init + : diag::ext_constexpr_ctor_missing_init); + Diagnosed = true; + } + SemaRef.Diag(Field->getLocation(), + diag::note_constexpr_ctor_missing_init); + } else if (!SemaRef.getLangOpts().CPlusPlus2a) { + return false; } - SemaRef.Diag(Field->getLocation(), diag::note_constexpr_ctor_missing_init); } else if (Field->isAnonymousStructOrUnion()) { const RecordDecl *RD = Field->getType()->castAs<RecordType>()->getDecl(); for (auto *I : RD->fields()) // If an anonymous union contains an anonymous struct of which any member // is initialized, all members must be initialized. if (!RD->isUnion() || Inits.count(I)) - CheckConstexprCtorInitializer(SemaRef, Dcl, I, Inits, Diagnosed); + if (!CheckConstexprCtorInitializer(SemaRef, Dcl, I, Inits, Diagnosed, + Kind)) + return false; } + return true; } /// Check the provided statement is allowed in a constexpr function @@ -1834,7 +1962,8 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef, static bool CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, SmallVectorImpl<SourceLocation> &ReturnStmts, - SourceLocation &Cxx1yLoc, SourceLocation &Cxx2aLoc) { + SourceLocation &Cxx1yLoc, SourceLocation &Cxx2aLoc, + Sema::CheckConstexprKind Kind) { // - its function-body shall be [...] a compound-statement that contains only switch (S->getStmtClass()) { case Stmt::NullStmtClass: @@ -1847,7 +1976,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, // - using-directives, // - typedef declarations and alias-declarations that do not define // classes or enumerations, - if (!CheckConstexprDeclStmt(SemaRef, Dcl, cast<DeclStmt>(S), Cxx1yLoc)) + if (!CheckConstexprDeclStmt(SemaRef, Dcl, cast<DeclStmt>(S), Cxx1yLoc, Kind)) return false; return true; @@ -1871,7 +2000,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, CompoundStmt *CompStmt = cast<CompoundStmt>(S); for (auto *BodyIt : CompStmt->body()) { if (!CheckConstexprFunctionStmt(SemaRef, Dcl, BodyIt, ReturnStmts, - Cxx1yLoc, Cxx2aLoc)) + Cxx1yLoc, Cxx2aLoc, Kind)) return false; } return true; @@ -1889,11 +2018,11 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, IfStmt *If = cast<IfStmt>(S); if (!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getThen(), ReturnStmts, - Cxx1yLoc, Cxx2aLoc)) + Cxx1yLoc, Cxx2aLoc, Kind)) return false; if (If->getElse() && !CheckConstexprFunctionStmt(SemaRef, Dcl, If->getElse(), ReturnStmts, - Cxx1yLoc, Cxx2aLoc)) + Cxx1yLoc, Cxx2aLoc, Kind)) return false; return true; } @@ -1912,7 +2041,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, for (Stmt *SubStmt : S->children()) if (SubStmt && !CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts, - Cxx1yLoc, Cxx2aLoc)) + Cxx1yLoc, Cxx2aLoc, Kind)) return false; return true; @@ -1927,17 +2056,20 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, for (Stmt *SubStmt : S->children()) if (SubStmt && !CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts, - Cxx1yLoc, Cxx2aLoc)) + Cxx1yLoc, Cxx2aLoc, Kind)) return false; return true; + case Stmt::GCCAsmStmtClass: + case Stmt::MSAsmStmtClass: + // C++2a allows inline assembly statements. case Stmt::CXXTryStmtClass: if (Cxx2aLoc.isInvalid()) Cxx2aLoc = S->getBeginLoc(); for (Stmt *SubStmt : S->children()) { if (SubStmt && !CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts, - Cxx1yLoc, Cxx2aLoc)) + Cxx1yLoc, Cxx2aLoc, Kind)) return false; } return true; @@ -1947,7 +2079,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, // try block check). if (!CheckConstexprFunctionStmt(SemaRef, Dcl, cast<CXXCatchStmt>(S)->getHandlerBlock(), - ReturnStmts, Cxx1yLoc, Cxx2aLoc)) + ReturnStmts, Cxx1yLoc, Cxx2aLoc, Kind)) return false; return true; @@ -1961,16 +2093,21 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, return true; } - SemaRef.Diag(S->getBeginLoc(), diag::err_constexpr_body_invalid_stmt) - << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval(); + if (Kind == Sema::CheckConstexprKind::Diagnose) { + SemaRef.Diag(S->getBeginLoc(), diag::err_constexpr_body_invalid_stmt) + << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval(); + } return false; } /// Check the body for the given constexpr function declaration only contains /// the permitted types of statement. C++11 [dcl.constexpr]p3,p4. /// -/// \return true if the body is OK, false if we have diagnosed a problem. -bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { +/// \return true if the body is OK, false if we have found or diagnosed a +/// problem. +static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, + Stmt *Body, + Sema::CheckConstexprKind Kind) { SmallVector<SourceLocation, 4> ReturnStmts; if (isa<CXXTryStmt>(Body)) { @@ -1986,11 +2123,20 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { // // This restriction is lifted in C++2a, as long as inner statements also // apply the general constexpr rules. - Diag(Body->getBeginLoc(), - !getLangOpts().CPlusPlus2a - ? diag::ext_constexpr_function_try_block_cxx2a - : diag::warn_cxx17_compat_constexpr_function_try_block) - << isa<CXXConstructorDecl>(Dcl); + switch (Kind) { + case Sema::CheckConstexprKind::CheckValid: + if (!SemaRef.getLangOpts().CPlusPlus2a) + return false; + break; + + case Sema::CheckConstexprKind::Diagnose: + SemaRef.Diag(Body->getBeginLoc(), + !SemaRef.getLangOpts().CPlusPlus2a + ? diag::ext_constexpr_function_try_block_cxx2a + : diag::warn_cxx17_compat_constexpr_function_try_block) + << isa<CXXConstructorDecl>(Dcl); + break; + } } // - its function-body shall be [...] a compound-statement that contains only @@ -2001,23 +2147,30 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { SourceLocation Cxx1yLoc, Cxx2aLoc; for (Stmt *SubStmt : Body->children()) { if (SubStmt && - !CheckConstexprFunctionStmt(*this, Dcl, SubStmt, ReturnStmts, - Cxx1yLoc, Cxx2aLoc)) + !CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts, + Cxx1yLoc, Cxx2aLoc, Kind)) return false; } - if (Cxx2aLoc.isValid()) - Diag(Cxx2aLoc, - getLangOpts().CPlusPlus2a + if (Kind == Sema::CheckConstexprKind::CheckValid) { + // If this is only valid as an extension, report that we don't satisfy the + // constraints of the current language. + if ((Cxx2aLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus2a) || + (Cxx1yLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus17)) + return false; + } else if (Cxx2aLoc.isValid()) { + SemaRef.Diag(Cxx2aLoc, + SemaRef.getLangOpts().CPlusPlus2a ? diag::warn_cxx17_compat_constexpr_body_invalid_stmt : diag::ext_constexpr_body_invalid_stmt_cxx2a) << isa<CXXConstructorDecl>(Dcl); - if (Cxx1yLoc.isValid()) - Diag(Cxx1yLoc, - getLangOpts().CPlusPlus14 + } else if (Cxx1yLoc.isValid()) { + SemaRef.Diag(Cxx1yLoc, + SemaRef.getLangOpts().CPlusPlus14 ? diag::warn_cxx11_compat_constexpr_body_invalid_stmt : diag::ext_constexpr_body_invalid_stmt) << isa<CXXConstructorDecl>(Dcl); + } if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Dcl)) { @@ -2031,8 +2184,15 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { if (RD->isUnion()) { if (Constructor->getNumCtorInitializers() == 0 && RD->hasVariantMembers()) { - Diag(Dcl->getLocation(), diag::err_constexpr_union_ctor_no_init); - return false; + if (Kind == Sema::CheckConstexprKind::Diagnose) { + SemaRef.Diag( + Dcl->getLocation(), + SemaRef.getLangOpts().CPlusPlus2a + ? diag::warn_cxx17_compat_constexpr_union_ctor_no_init + : diag::ext_constexpr_union_ctor_no_init); + } else if (!SemaRef.getLangOpts().CPlusPlus2a) { + return false; + } } } else if (!Constructor->isDependentContext() && !Constructor->isDelegatingConstructor()) { @@ -2068,9 +2228,9 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { bool Diagnosed = false; for (auto *I : RD->fields()) - CheckConstexprCtorInitializer(*this, Dcl, I, Inits, Diagnosed); - if (Diagnosed) - return false; + if (!CheckConstexprCtorInitializer(SemaRef, Dcl, I, Inits, Diagnosed, + Kind)) + return false; } } } else { @@ -2079,22 +2239,45 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { // statement. We still do, unless the return type might be void, because // otherwise if there's no return statement, the function cannot // be used in a core constant expression. - bool OK = getLangOpts().CPlusPlus14 && + bool OK = SemaRef.getLangOpts().CPlusPlus14 && (Dcl->getReturnType()->isVoidType() || Dcl->getReturnType()->isDependentType()); - Diag(Dcl->getLocation(), - OK ? diag::warn_cxx11_compat_constexpr_body_no_return - : diag::err_constexpr_body_no_return) - << Dcl->isConsteval(); - if (!OK) - return false; + switch (Kind) { + case Sema::CheckConstexprKind::Diagnose: + SemaRef.Diag(Dcl->getLocation(), + OK ? diag::warn_cxx11_compat_constexpr_body_no_return + : diag::err_constexpr_body_no_return) + << Dcl->isConsteval(); + if (!OK) + return false; + break; + + case Sema::CheckConstexprKind::CheckValid: + // The formal requirements don't include this rule in C++14, even + // though the "must be able to produce a constant expression" rules + // still imply it in some cases. + if (!SemaRef.getLangOpts().CPlusPlus14) + return false; + break; + } } else if (ReturnStmts.size() > 1) { - Diag(ReturnStmts.back(), - getLangOpts().CPlusPlus14 - ? diag::warn_cxx11_compat_constexpr_body_multiple_return - : diag::ext_constexpr_body_multiple_return); - for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I) - Diag(ReturnStmts[I], diag::note_constexpr_body_previous_return); + switch (Kind) { + case Sema::CheckConstexprKind::Diagnose: + SemaRef.Diag( + ReturnStmts.back(), + SemaRef.getLangOpts().CPlusPlus14 + ? diag::warn_cxx11_compat_constexpr_body_multiple_return + : diag::ext_constexpr_body_multiple_return); + for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I) + SemaRef.Diag(ReturnStmts[I], + diag::note_constexpr_body_previous_return); + break; + + case Sema::CheckConstexprKind::CheckValid: + if (!SemaRef.getLangOpts().CPlusPlus14) + return false; + break; + } } } @@ -2108,12 +2291,17 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { // C++11 [dcl.constexpr]p4: // - every constructor involved in initializing non-static data members and // base class sub-objects shall be a constexpr constructor. + // + // Note that this rule is distinct from the "requirements for a constexpr + // function", so is not checked in CheckValid mode. SmallVector<PartialDiagnosticAt, 8> Diags; - if (!Expr::isPotentialConstantExpr(Dcl, Diags)) { - Diag(Dcl->getLocation(), diag::ext_constexpr_function_never_constant_expr) - << isa<CXXConstructorDecl>(Dcl); + if (Kind == Sema::CheckConstexprKind::Diagnose && + !Expr::isPotentialConstantExpr(Dcl, Diags)) { + SemaRef.Diag(Dcl->getLocation(), + diag::ext_constexpr_function_never_constant_expr) + << isa<CXXConstructorDecl>(Dcl); for (size_t I = 0, N = Diags.size(); I != N; ++I) - Diag(Diags[I].first, Diags[I].second); + SemaRef.Diag(Diags[I].first, Diags[I].second); // Don't return false here: we allow this for compatibility in // system headers. } @@ -2298,7 +2486,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, } // If the base class is polymorphic or isn't empty, the new one is/isn't, too. - RecordDecl *BaseDecl = BaseType->getAs<RecordType>()->getDecl(); + RecordDecl *BaseDecl = BaseType->castAs<RecordType>()->getDecl(); assert(BaseDecl && "Record type has no declaration"); BaseDecl = BaseDecl->getDefinition(); assert(BaseDecl && "Base type is not incomplete, but has no definition"); @@ -2381,7 +2569,7 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, Diag(AL.getLoc(), AL.getKind() == ParsedAttr::UnknownAttribute ? (unsigned)diag::warn_unknown_attribute_ignored : (unsigned)diag::err_base_specifier_attribute) - << AL.getName(); + << AL; } TypeSourceInfo *TInfo = nullptr; @@ -3225,10 +3413,12 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, } if (VS.isOverrideSpecified()) - Member->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context, 0)); + Member->addAttr(OverrideAttr::Create(Context, VS.getOverrideLoc(), + AttributeCommonInfo::AS_Keyword)); if (VS.isFinalSpecified()) - Member->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context, - VS.isFinalSpelledSealed())); + Member->addAttr(FinalAttr::Create( + Context, VS.getFinalLoc(), AttributeCommonInfo::AS_Keyword, + static_cast<FinalAttr::Spelling>(VS.isFinalSpelledSealed()))); if (VS.getLastLocation().isValid()) { // Update the end location of a method that has a virt-specifiers. @@ -3826,7 +4016,7 @@ public: } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<MemInitializerValidatorCCC>(*this); + return std::make_unique<MemInitializerValidatorCCC>(*this); } private: @@ -5801,14 +5991,10 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { TSK != TSK_ExplicitInstantiationDefinition) { if (ClassExported) { NewAttr = ::new (getASTContext()) - DLLExportStaticLocalAttr(ClassAttr->getRange(), - getASTContext(), - ClassAttr->getSpellingListIndex()); + DLLExportStaticLocalAttr(getASTContext(), *ClassAttr); } else { NewAttr = ::new (getASTContext()) - DLLImportStaticLocalAttr(ClassAttr->getRange(), - getASTContext(), - ClassAttr->getSpellingListIndex()); + DLLImportStaticLocalAttr(getASTContext(), *ClassAttr); } } else { NewAttr = cast<InheritableAttr>(ClassAttr->clone(getASTContext())); @@ -6117,6 +6303,22 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { } } + // Warn if the class has a final destructor but is not itself marked final. + if (!Record->hasAttr<FinalAttr>()) { + if (const CXXDestructorDecl *dtor = Record->getDestructor()) { + if (const FinalAttr *FA = dtor->getAttr<FinalAttr>()) { + Diag(FA->getLocation(), diag::warn_final_dtor_non_final_class) + << FA->isSpelledAsSealed() + << FixItHint::CreateInsertion( + getLocForEndOfToken(Record->getLocation()), + (FA->isSpelledAsSealed() ? " sealed" : " final")); + Diag(Record->getLocation(), + diag::note_final_dtor_non_final_class_silence) + << Context.getRecordType(Record) << FA->isSpelledAsSealed(); + } + } + } + // See if trivial_abi has to be dropped. if (Record->hasAttr<TrivialABIAttr>()) checkIllFormedTrivialABIStruct(*Record); @@ -6165,10 +6367,16 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { M->dropAttr<DLLExportAttr>(); if (M->hasAttr<DLLExportAttr>()) { - DefineImplicitSpecialMember(*this, M, M->getLocation()); - ActOnFinishInlineFunctionDef(M); + // Define after any fields with in-class initializers have been parsed. + DelayedDllExportMemberFunctions.push_back(M); } } + + // Define defaulted constexpr virtual functions that override a base class + // function right away. + // FIXME: We can defer doing this until the vtable is marked as used. + if (M->isDefaulted() && M->isConstexpr() && M->size_overridden_methods()) + DefineImplicitSpecialMember(*this, M, M->getLocation()); }; bool HasMethodWithOverrideControl = false, @@ -6382,6 +6590,8 @@ specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, if (CSM == Sema::CXXDefaultConstructor) return ClassDecl->hasConstexprDefaultConstructor(); + if (CSM == Sema::CXXDestructor) + return ClassDecl->hasConstexprDestructor(); Sema::SpecialMemberOverloadResult SMOR = lookupCallFromSpecialMember(S, ClassDecl, CSM, Quals, ConstRHS); @@ -6430,6 +6640,8 @@ static bool defaultedSpecialMemberIsConstexpr( break; case Sema::CXXDestructor: + return ClassDecl->defaultedDestructorIsConstexpr(); + case Sema::CXXInvalid: return false; } @@ -6682,13 +6894,14 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { // Do not apply this rule to members of class templates, since core issue 1358 // makes such functions always instantiate to constexpr functions. For // functions which cannot be constexpr (for non-constructors in C++11 and for - // destructors in C++1y), this is checked elsewhere. + // destructors in C++14 and C++17), this is checked elsewhere. // // FIXME: This should not apply if the member is deleted. bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM, HasConstParam); - if ((getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(MD) - : isa<CXXConstructorDecl>(MD)) && + if ((getLangOpts().CPlusPlus2a || + (getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(MD) + : isa<CXXConstructorDecl>(MD))) && MD->isConstexpr() && !Constexpr && MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) { Diag(MD->getBeginLoc(), MD->isConsteval() @@ -7798,7 +8011,7 @@ public: /// to be used with CXXRecordDecl::lookupInBases(). bool operator()(const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { RecordDecl *BaseRecord = - Specifier->getType()->getAs<RecordType>()->getDecl(); + Specifier->getType()->castAs<RecordType>()->getDecl(); DeclarationName Name = Method->getDeclName(); assert(Name.getNameKind() == DeclarationName::Identifier); @@ -7966,8 +8179,7 @@ void Sema::ActOnFinishCXXMemberSpecification( if (AL.getKind() != ParsedAttr::AT_Visibility) continue; AL.setInvalid(); - Diag(AL.getLoc(), diag::warn_attribute_after_definition_ignored) - << AL.getName(); + Diag(AL.getLoc(), diag::warn_attribute_after_definition_ignored) << AL; } ActOnFields(S, RLoc, TagDecl, llvm::makeArrayRef( @@ -9386,7 +9598,7 @@ public: } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<NamespaceValidatorCCC>(*this); + return std::make_unique<NamespaceValidatorCCC>(*this); } }; @@ -9882,7 +10094,8 @@ static CXXBaseSpecifier *findDirectBaseWithType(CXXRecordDecl *Derived, QualType DesiredBase, bool &AnyDependentBases) { // Check whether the named type is a direct base class. - CanQualType CanonicalDesiredBase = DesiredBase->getCanonicalTypeUnqualified(); + CanQualType CanonicalDesiredBase = DesiredBase->getCanonicalTypeUnqualified() + .getUnqualifiedType(); for (auto &Base : Derived->bases()) { CanQualType BaseType = Base.getType()->getCanonicalTypeUnqualified(); if (CanonicalDesiredBase == BaseType) @@ -9965,7 +10178,7 @@ public: } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<UsingValidatorCCC>(*this); + return std::make_unique<UsingValidatorCCC>(*this); } private: @@ -11311,6 +11524,10 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { if (DSM.isAlreadyBeingDeclared()) return nullptr; + bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl, + CXXDestructor, + false); + // Create the actual destructor declaration. CanQualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); @@ -11318,10 +11535,11 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { DeclarationName Name = Context.DeclarationNames.getCXXDestructorName(ClassType); DeclarationNameInfo NameInfo(Name, ClassLoc); - CXXDestructorDecl *Destructor - = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, - QualType(), nullptr, /*isInline=*/true, - /*isImplicitlyDeclared=*/true); + CXXDestructorDecl *Destructor = + CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, + QualType(), nullptr, /*isInline=*/true, + /*isImplicitlyDeclared=*/true, + Constexpr ? CSK_constexpr : CSK_unspecified); Destructor->setAccess(AS_public); Destructor->setDefaulted(); @@ -11419,6 +11637,21 @@ void Sema::ActOnFinishCXXMemberDecls() { void Sema::ActOnFinishCXXNonNestedClass(Decl *D) { referenceDLLExportedClassMethods(); + + if (!DelayedDllExportMemberFunctions.empty()) { + SmallVector<CXXMethodDecl*, 4> WorkList; + std::swap(DelayedDllExportMemberFunctions, WorkList); + for (CXXMethodDecl *M : WorkList) { + DefineImplicitSpecialMember(*this, M, M->getLocation()); + + // Pass the method to the consumer to get emitted. This is not necessary + // for explicit instantiation definitions, as they will get emitted + // anyway. + if (M->getParent()->getTemplateSpecializationKind() != + TSK_ExplicitInstantiationDefinition) + ActOnFinishInlineFunctionDef(M); + } + } } void Sema::referenceDLLExportedClassMethods() { @@ -11619,7 +11852,8 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T, const Type *E = T->getBaseElementTypeUnsafe(); bool NeedsCollectableMemCpy = - E->isRecordType() && E->getAs<RecordType>()->getDecl()->hasObjectMember(); + E->isRecordType() && + E->castAs<RecordType>()->getDecl()->hasObjectMember(); // Create a reference to the __builtin_objc_memmove_collectable function StringRef MemCpyName = NeedsCollectableMemCpy ? @@ -13172,6 +13406,20 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { } if (Destructor->isTrivial()) return; + + // If the destructor is constexpr, check whether the variable has constant + // destruction now. + if (Destructor->isConstexpr() && VD->getInit() && + !VD->getInit()->isValueDependent() && VD->evaluateValue()) { + SmallVector<PartialDiagnosticAt, 8> Notes; + if (!VD->evaluateDestruction(Notes) && VD->isConstexpr()) { + Diag(VD->getLocation(), + diag::err_constexpr_var_requires_const_destruction) << VD; + for (unsigned I = 0, N = Notes.size(); I != N; ++I) + Diag(Notes[I].first, Notes[I].second); + } + } + if (!VD->hasGlobalStorage()) return; // Emit warning for non-trivial dtor in global scope (a real global, @@ -13762,6 +14010,10 @@ 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(); @@ -14014,8 +14266,17 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, if (Converted.isInvalid()) Failed = true; + ExprResult FullAssertExpr = + ActOnFinishFullExpr(Converted.get(), StaticAssertLoc, + /*DiscardedValue*/ false, + /*IsConstexpr*/ true); + if (FullAssertExpr.isInvalid()) + Failed = true; + else + AssertExpr = FullAssertExpr.get(); + llvm::APSInt Cond; - if (!Failed && VerifyIntegerConstantExpression(Converted.get(), &Cond, + if (!Failed && VerifyIntegerConstantExpression(AssertExpr, &Cond, diag::err_static_assert_expression_is_not_constant, /*AllowFold=*/false).isInvalid()) Failed = true; @@ -14041,16 +14302,16 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, } Failed = true; } + } else { + ExprResult FullAssertExpr = ActOnFinishFullExpr(AssertExpr, StaticAssertLoc, + /*DiscardedValue*/false, + /*IsConstexpr*/true); + if (FullAssertExpr.isInvalid()) + Failed = true; + else + AssertExpr = FullAssertExpr.get(); } - ExprResult FullAssertExpr = ActOnFinishFullExpr(AssertExpr, StaticAssertLoc, - /*DiscardedValue*/false, - /*IsConstexpr*/true); - if (FullAssertExpr.isInvalid()) - Failed = true; - else - AssertExpr = FullAssertExpr.get(); - Decl *Decl = StaticAssertDecl::Create(Context, CurContext, StaticAssertLoc, AssertExpr, AssertMessage, RParenLoc, Failed); @@ -15282,8 +15543,8 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, return; for (const auto &I : RD->bases()) { - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl()); + const auto *Base = + cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl()); if (Base->getNumVBases() == 0) continue; MarkVirtualMembersReferenced(Loc, Base); diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index e629837eb71d..db594bbd21dd 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -512,7 +512,7 @@ class ObjCInterfaceValidatorCCC final : public CorrectionCandidateCallback { } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<ObjCInterfaceValidatorCCC>(*this); + return std::make_unique<ObjCInterfaceValidatorCCC>(*this); } private: @@ -586,7 +586,7 @@ ActOnSuperClassOfClassInterface(Scope *S, dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { QualType T = TDecl->getUnderlyingType(); if (T->isObjCObjectType()) { - if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) { + if (NamedDecl *IDecl = T->castAs<ObjCObjectType>()->getInterface()) { SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl); SuperClassType = Context.getTypeDeclType(TDecl); @@ -1151,7 +1151,7 @@ Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc, dyn_cast_or_null<TypedefNameDecl>(CDeclU)) { QualType T = TDecl->getUnderlyingType(); if (T->isObjCObjectType()) { - if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) { + if (NamedDecl *IDecl = T->castAs<ObjCObjectType>()->getInterface()) { ClassName = IDecl->getIdentifier(); CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation, LookupOrdinaryName, @@ -1387,7 +1387,7 @@ class ObjCTypeArgOrProtocolValidatorCCC final } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<ObjCTypeArgOrProtocolValidatorCCC>(*this); + return std::make_unique<ObjCTypeArgOrProtocolValidatorCCC>(*this); } }; } // end anonymous namespace @@ -2275,9 +2275,7 @@ static bool isObjCTypeSubstitutable(ASTContext &Context, // stricter definition so it is not substitutable for id<A>. if (B->isObjCQualifiedIdType()) { return A->isObjCQualifiedIdType() && - Context.ObjCQualifiedIdTypesAreCompatible(QualType(A, 0), - QualType(B,0), - false); + Context.ObjCQualifiedIdTypesAreCompatible(A, B, false); } /* @@ -4878,7 +4876,7 @@ VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType T, } else if (!T->isObjCObjectPointerType()) { Invalid = true; Diag(IdLoc, diag::err_catch_param_not_objc_type); - } else if (!T->getAs<ObjCObjectPointerType>()->getInterfaceType()) { + } else if (!T->castAs<ObjCObjectPointerType>()->getInterfaceType()) { Invalid = true; Diag(IdLoc, diag::err_catch_param_not_objc_type); } diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 9fd924a8cad0..c1abf099e9f2 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -149,12 +149,12 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) { // In Microsoft mode, downgrade this to a warning. unsigned DiagID = diag::err_incomplete_in_exception_spec; bool ReturnValueOnError = true; - if (getLangOpts().MicrosoftExt) { + if (getLangOpts().MSVCCompat) { DiagID = diag::ext_incomplete_in_exception_spec; ReturnValueOnError = false; } if (!(PointeeT->isRecordType() && - PointeeT->getAs<RecordType>()->isBeingDefined()) && + PointeeT->castAs<RecordType>()->isBeingDefined()) && RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range)) return ReturnValueOnError; @@ -263,8 +263,7 @@ static bool hasImplicitExceptionSpec(FunctionDecl *Decl) { if (!Decl->getTypeSourceInfo()) return isa<CXXDestructorDecl>(Decl); - const FunctionProtoType *Ty = - Decl->getTypeSourceInfo()->getType()->getAs<FunctionProtoType>(); + auto *Ty = Decl->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>(); return !Ty->hasExceptionSpec(); } @@ -282,7 +281,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { unsigned DiagID = diag::err_mismatched_exception_spec; bool ReturnValueOnError = true; - if (getLangOpts().MicrosoftExt) { + if (getLangOpts().MSVCCompat) { DiagID = diag::ext_mismatched_exception_spec; ReturnValueOnError = false; } @@ -371,7 +370,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { NewProto->getExtProtoInfo().withExceptionSpec(ESI))); } - if (getLangOpts().MicrosoftExt && ESI.Type != EST_DependentNoexcept) { + if (getLangOpts().MSVCCompat && ESI.Type != EST_DependentNoexcept) { // Allow missing exception specifications in redeclarations as an extension. DiagID = diag::ext_ms_missing_exception_specification; ReturnValueOnError = false; @@ -473,14 +472,14 @@ bool Sema::CheckEquivalentExceptionSpec( return false; unsigned DiagID = diag::err_mismatched_exception_spec; - if (getLangOpts().MicrosoftExt) + if (getLangOpts().MSVCCompat) DiagID = diag::ext_mismatched_exception_spec; bool Result = CheckEquivalentExceptionSpecImpl( *this, PDiag(DiagID), PDiag(diag::note_previous_declaration), Old, OldLoc, New, NewLoc); // In Microsoft mode, mismatching exception specifications just cause a warning. - if (getLangOpts().MicrosoftExt) + if (getLangOpts().MSVCCompat) return false; return Result; } @@ -959,15 +958,15 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, } unsigned DiagID = diag::err_override_exception_spec; - if (getLangOpts().MicrosoftExt) + if (getLangOpts().MSVCCompat) DiagID = diag::ext_override_exception_spec; return CheckExceptionSpecSubset(PDiag(DiagID), PDiag(diag::err_deep_exception_specs_differ), PDiag(diag::note_overridden_virtual_function), PDiag(diag::ext_override_exception_spec), - Old->getType()->getAs<FunctionProtoType>(), + Old->getType()->castAs<FunctionProtoType>(), Old->getLocation(), - New->getType()->getAs<FunctionProtoType>(), + New->getType()->castAs<FunctionProtoType>(), New->getLocation()); } @@ -1201,6 +1200,7 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::CoyieldExprClass: case Expr::CXXConstCastExprClass: case Expr::CXXReinterpretCastExprClass: + case Expr::CXXRewrittenBinaryOperatorClass: case Expr::BuiltinBitCastExprClass: case Expr::CXXStdInitializerListExprClass: case Expr::DesignatedInitExprClass: @@ -1314,6 +1314,7 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::SizeOfPackExprClass: case Expr::StringLiteralClass: case Expr::SourceLocExprClass: + case Expr::ConceptSpecializationExprClass: // These expressions can never throw. return CT_Cannot; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index d8869ffe945a..e41cd5b6653a 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1990,16 +1990,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, R.clear(); } - // In Microsoft mode, if we are performing lookup from within a friend - // function definition declared at class scope then we must set - // DC to the lexical parent to be able to search into the parent - // class. - if (getLangOpts().MSVCCompat && isa<FunctionDecl>(DC) && - cast<FunctionDecl>(DC)->getFriendObjectKind() && - DC->getLexicalParent()->isRecord()) - DC = DC->getLexicalParent(); - else - DC = DC->getParent(); + DC = DC->getLookupParent(); } // We didn't find anything, so try to correct for a typo. @@ -2491,23 +2482,20 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr( return BuildDeclarationNameExpr(SS, R, /* ADL */ false); } -/// LookupInObjCMethod - The parser has read a name in, and Sema has -/// detected that we're currently inside an ObjC method. Perform some -/// additional lookup. +/// The parser has read a name in, and Sema has detected that we're currently +/// inside an ObjC method. Perform some additional checks and determine if we +/// should form a reference to an ivar. /// /// Ideally, most of this would be done by lookup, but there's /// actually quite a lot of extra work involved. -/// -/// Returns a null sentinel to indicate trivial success. -ExprResult -Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, - IdentifierInfo *II, bool AllowBuiltinCreation) { +DeclResult Sema::LookupIvarInObjCMethod(LookupResult &Lookup, Scope *S, + IdentifierInfo *II) { SourceLocation Loc = Lookup.getNameLoc(); ObjCMethodDecl *CurMethod = getCurMethodDecl(); // Check for error condition which is already reported. if (!CurMethod) - return ExprError(); + return DeclResult(true); // There are two cases to handle here. 1) scoped lookup could have failed, // in which case we should look for an ivar. 2) scoped lookup could have @@ -2535,18 +2523,10 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, ObjCIvarDecl *IV = nullptr; if (IFace && (IV = IFace->lookupInstanceVariable(II, ClassDeclared))) { // Diagnose using an ivar in a class method. - if (IsClassMethod) - return ExprError(Diag(Loc, diag::err_ivar_use_in_class_method) - << IV->getDeclName()); - - // If we're referencing an invalid decl, just return this as a silent - // error node. The error diagnostic was already emitted on the decl. - if (IV->isInvalidDecl()) - return ExprError(); - - // Check if referencing a field with __attribute__((deprecated)). - if (DiagnoseUseOfDecl(IV, Loc)) - return ExprError(); + if (IsClassMethod) { + Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName(); + return DeclResult(true); + } // Diagnose the use of an ivar outside of the declaring class. if (IV->getAccessControl() == ObjCIvarDecl::Private && @@ -2554,46 +2534,8 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, !getLangOpts().DebuggerSupport) Diag(Loc, diag::err_private_ivar_access) << IV->getDeclName(); - // FIXME: This should use a new expr for a direct reference, don't - // turn this into Self->ivar, just return a BareIVarExpr or something. - IdentifierInfo &II = Context.Idents.get("self"); - UnqualifiedId SelfName; - SelfName.setIdentifier(&II, SourceLocation()); - SelfName.setKind(UnqualifiedIdKind::IK_ImplicitSelfParam); - CXXScopeSpec SelfScopeSpec; - SourceLocation TemplateKWLoc; - ExprResult SelfExpr = - ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc, SelfName, - /*HasTrailingLParen=*/false, - /*IsAddressOfOperand=*/false); - if (SelfExpr.isInvalid()) - return ExprError(); - - SelfExpr = DefaultLvalueConversion(SelfExpr.get()); - if (SelfExpr.isInvalid()) - return ExprError(); - - MarkAnyDeclReferenced(Loc, IV, true); - - ObjCMethodFamily MF = CurMethod->getMethodFamily(); - if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize && - !IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV)) - Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName(); - - ObjCIvarRefExpr *Result = new (Context) - ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc, - IV->getLocation(), SelfExpr.get(), true, true); - - if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { - if (!isUnevaluatedContext() && - !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc)) - getCurFunction()->recordUseOfWeak(Result); - } - if (getLangOpts().ObjCAutoRefCount) - if (const BlockDecl *BD = CurContext->getInnermostBlockDecl()) - ImplicitlyRetainedSelfLocs.push_back({Loc, BD}); - - return Result; + // Success. + return IV; } } else if (CurMethod->isInstanceMethod()) { // We should warn if a local variable hides an ivar. @@ -2608,25 +2550,97 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, } else if (Lookup.isSingleResult() && Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()) { // If accessing a stand-alone ivar in a class method, this is an error. - if (const ObjCIvarDecl *IV = dyn_cast<ObjCIvarDecl>(Lookup.getFoundDecl())) - return ExprError(Diag(Loc, diag::err_ivar_use_in_class_method) - << IV->getDeclName()); - } - - if (Lookup.empty() && II && AllowBuiltinCreation) { - // FIXME. Consolidate this with similar code in LookupName. - if (unsigned BuiltinID = II->getBuiltinID()) { - if (!(getLangOpts().CPlusPlus && - Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))) { - NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, - S, Lookup.isForRedeclaration(), - Lookup.getNameLoc()); - if (D) Lookup.addDecl(D); - } + if (const ObjCIvarDecl *IV = + dyn_cast<ObjCIvarDecl>(Lookup.getFoundDecl())) { + Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName(); + return DeclResult(true); } } + + // Didn't encounter an error, didn't find an ivar. + return DeclResult(false); +} + +ExprResult Sema::BuildIvarRefExpr(Scope *S, SourceLocation Loc, + ObjCIvarDecl *IV) { + ObjCMethodDecl *CurMethod = getCurMethodDecl(); + assert(CurMethod && CurMethod->isInstanceMethod() && + "should not reference ivar from this context"); + + ObjCInterfaceDecl *IFace = CurMethod->getClassInterface(); + assert(IFace && "should not reference ivar from this context"); + + // If we're referencing an invalid decl, just return this as a silent + // error node. The error diagnostic was already emitted on the decl. + if (IV->isInvalidDecl()) + return ExprError(); + + // Check if referencing a field with __attribute__((deprecated)). + if (DiagnoseUseOfDecl(IV, Loc)) + return ExprError(); + + // FIXME: This should use a new expr for a direct reference, don't + // turn this into Self->ivar, just return a BareIVarExpr or something. + IdentifierInfo &II = Context.Idents.get("self"); + UnqualifiedId SelfName; + SelfName.setIdentifier(&II, SourceLocation()); + SelfName.setKind(UnqualifiedIdKind::IK_ImplicitSelfParam); + CXXScopeSpec SelfScopeSpec; + SourceLocation TemplateKWLoc; + ExprResult SelfExpr = + ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc, SelfName, + /*HasTrailingLParen=*/false, + /*IsAddressOfOperand=*/false); + if (SelfExpr.isInvalid()) + return ExprError(); + + SelfExpr = DefaultLvalueConversion(SelfExpr.get()); + if (SelfExpr.isInvalid()) + return ExprError(); + + MarkAnyDeclReferenced(Loc, IV, true); + + ObjCMethodFamily MF = CurMethod->getMethodFamily(); + if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize && + !IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV)) + Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName(); + + ObjCIvarRefExpr *Result = new (Context) + ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc, + IV->getLocation(), SelfExpr.get(), true, true); + + if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { + if (!isUnevaluatedContext() && + !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc)) + getCurFunction()->recordUseOfWeak(Result); + } + if (getLangOpts().ObjCAutoRefCount) + if (const BlockDecl *BD = CurContext->getInnermostBlockDecl()) + ImplicitlyRetainedSelfLocs.push_back({Loc, BD}); + + return Result; +} + +/// The parser has read a name in, and Sema has detected that we're currently +/// inside an ObjC method. Perform some additional checks and determine if we +/// should form a reference to an ivar. If so, build an expression referencing +/// that ivar. +ExprResult +Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, + IdentifierInfo *II, bool AllowBuiltinCreation) { + // FIXME: Integrate this lookup step into LookupParsedName. + DeclResult Ivar = LookupIvarInObjCMethod(Lookup, S, II); + if (Ivar.isInvalid()) + return ExprError(); + if (Ivar.isUsable()) + return BuildIvarRefExpr(S, Lookup.getNameLoc(), + cast<ObjCIvarDecl>(Ivar.get())); + + if (Lookup.empty() && II && AllowBuiltinCreation) + LookupBuiltin(Lookup); + // Sentinel value saying that we didn't do anything special. - return ExprResult((Expr *)nullptr); + return ExprResult(false); } /// Cast a base object to a member's actual type. @@ -3216,13 +3230,15 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, SmallString<32> RawChars; ConvertUTF8ToWideString(Context.getTypeSizeInChars(ResTy).getQuantity(), Str, RawChars); - ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, + ResTy = Context.getConstantArrayType(ResTy, LengthI, nullptr, + ArrayType::Normal, /*IndexTypeQuals*/ 0); SL = StringLiteral::Create(Context, RawChars, StringLiteral::Wide, /*Pascal*/ false, ResTy, Loc); } else { ResTy = Context.adjustStringLiteralBaseType(Context.CharTy.withConst()); - ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, + ResTy = Context.getConstantArrayType(ResTy, LengthI, nullptr, + ArrayType::Normal, /*IndexTypeQuals*/ 0); SL = StringLiteral::Create(Context, Str, StringLiteral::Ascii, /*Pascal*/ false, ResTy, Loc); @@ -3462,7 +3478,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { unsigned Length = Literal.getUDSuffixOffset(); QualType StrTy = Context.getConstantArrayType( Context.adjustStringLiteralBaseType(Context.CharTy.withConst()), - llvm::APInt(32, Length + 1), ArrayType::Normal, 0); + llvm::APInt(32, Length + 1), nullptr, ArrayType::Normal, 0); Expr *Lit = StringLiteral::Create( Context, StringRef(TokSpelling.data(), Length), StringLiteral::Ascii, /*Pascal*/false, StrTy, &TokLoc, 1); @@ -3808,6 +3824,16 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, QualType ExprTy = E->getType(); assert(!ExprTy->isReferenceType()); + bool IsUnevaluatedOperand = + (ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf || + ExprKind == UETT_PreferredAlignOf); + if (IsUnevaluatedOperand) { + ExprResult Result = CheckUnevaluatedOperand(E); + if (Result.isInvalid()) + return true; + E = Result.get(); + } + if (ExprKind == UETT_VecStep) return CheckVecStepTraitOperandType(*this, ExprTy, E->getExprLoc(), E->getSourceRange()); @@ -3845,9 +3871,8 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, // The operand for sizeof and alignof is in an unevaluated expression context, // so side effects could result in unintended consequences. - if ((ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf || - ExprKind == UETT_PreferredAlignOf) && - !inTemplateInstantiation() && E->HasSideEffects(Context, false)) + if (IsUnevaluatedOperand && !inTemplateInstantiation() && + E->HasSideEffects(Context, false)) Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context); if (CheckObjCTraitOperandConstraints(*this, ExprTy, E->getExprLoc(), @@ -3946,8 +3971,6 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType, } static bool CheckAlignOfExpr(Sema &S, Expr *E, UnaryExprOrTypeTrait ExprKind) { - E = E->IgnoreParens(); - // Cannot know anything else if the expression is dependent. if (E->isTypeDependent()) return false; @@ -3959,9 +3982,10 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E, UnaryExprOrTypeTrait ExprKind) { } ValueDecl *D = nullptr; - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + Expr *Inner = E->IgnoreParens(); + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Inner)) { D = DRE->getDecl(); - } else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + } else if (MemberExpr *ME = dyn_cast<MemberExpr>(Inner)) { D = ME->getMemberDecl(); } @@ -4026,7 +4050,7 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T, #define NON_CANONICAL_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) case Type::Class: #define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) -#include "clang/AST/TypeNodes.def" +#include "clang/AST/TypeNodes.inc" T = QualType(); break; // These types are never variably-modified. @@ -4317,6 +4341,15 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, base = result.get(); } + // A comma-expression as the index is deprecated in C++2a onwards. + if (getLangOpts().CPlusPlus2a && + ((isa<BinaryOperator>(idx) && cast<BinaryOperator>(idx)->isCommaOp()) || + (isa<CXXOperatorCallExpr>(idx) && + cast<CXXOperatorCallExpr>(idx)->getOperator() == OO_Comma))) { + Diag(idx->getExprLoc(), diag::warn_deprecated_comma_subscript) + << SourceRange(base->getBeginLoc(), rbLoc); + } + // Handle any non-overload placeholder types in the base and index // expressions. We can't handle overloads here because the other // operand might be an overloadable type, in which case the overload @@ -4823,8 +4856,10 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, // default argument expression appears. ContextRAII SavedContext(*this, FD); LocalInstantiationScope Local(*this); - Result = SubstInitializer(UninstExpr, MutiLevelArgList, - /*DirectInit*/false); + runWithSufficientStackSpace(CallLoc, [&] { + Result = SubstInitializer(UninstExpr, MutiLevelArgList, + /*DirectInit*/false); + }); } if (Result.isInvalid()) return true; @@ -4935,7 +4970,7 @@ public: } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<FunctionCallCCC>(*this); + return std::make_unique<FunctionCallCCC>(*this); } private: @@ -5296,6 +5331,11 @@ static bool isPlaceholderToRemoveAsArg(QualType type) { #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ case BuiltinType::Id: #include "clang/Basic/OpenCLExtensionTypes.def" + // In practice we'll never use this, since all SVE types are sugared + // via TypedefTypes rather than exposed directly as BuiltinTypes. +#define SVE_TYPE(Name, Id, SingletonId) \ + case BuiltinType::Id: +#include "clang/Basic/AArch64SVEACLETypes.def" #define PLACEHOLDER_TYPE(ID, SINGLETON_ID) #define BUILTIN_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: #include "clang/AST/BuiltinTypes.def" @@ -5366,8 +5406,8 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context, QualType DeclType = FDecl->getType(); const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(DeclType); - if (!Context.BuiltinInfo.hasPtrArgsOrResult(FDecl->getBuiltinID()) || - !FT || FT->isVariadic() || ArgExprs.size() != FT->getNumParams()) + if (!Context.BuiltinInfo.hasPtrArgsOrResult(FDecl->getBuiltinID()) || !FT || + ArgExprs.size() < FT->getNumParams()) return nullptr; bool NeedsNewDecl = false; @@ -5406,6 +5446,7 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context, return nullptr; FunctionProtoType::ExtProtoInfo EPI; + EPI.Variadic = FT->isVariadic(); QualType OverloadTy = Context.getFunctionType(FT->getReturnType(), OverloadParams, EPI); DeclContext *Parent = FDecl->getParent(); @@ -5883,7 +5924,9 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, << FDecl << Fn->getSourceRange()); // CUDA: Kernel function must have 'void' return type - if (!FuncT->getReturnType()->isVoidType()) + if (!FuncT->getReturnType()->isVoidType() && + !FuncT->getReturnType()->getAs<AutoType>() && + !FuncT->getReturnType()->isInstantiationDependentType()) return ExprError(Diag(LParenLoc, diag::err_kern_type_not_void_return) << Fn->getType() << Fn->getSourceRange()); } else { @@ -6103,6 +6146,77 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, ExprResult Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, SourceLocation RBraceLoc) { + // Only produce each kind of designated initialization diagnostic once. + SourceLocation FirstDesignator; + bool DiagnosedArrayDesignator = false; + bool DiagnosedNestedDesignator = false; + bool DiagnosedMixedDesignator = false; + + // Check that any designated initializers are syntactically valid in the + // current language mode. + for (unsigned I = 0, E = InitArgList.size(); I != E; ++I) { + if (auto *DIE = dyn_cast<DesignatedInitExpr>(InitArgList[I])) { + if (FirstDesignator.isInvalid()) + FirstDesignator = DIE->getBeginLoc(); + + if (!getLangOpts().CPlusPlus) + break; + + if (!DiagnosedNestedDesignator && DIE->size() > 1) { + DiagnosedNestedDesignator = true; + Diag(DIE->getBeginLoc(), diag::ext_designated_init_nested) + << DIE->getDesignatorsSourceRange(); + } + + for (auto &Desig : DIE->designators()) { + if (!Desig.isFieldDesignator() && !DiagnosedArrayDesignator) { + DiagnosedArrayDesignator = true; + Diag(Desig.getBeginLoc(), diag::ext_designated_init_array) + << Desig.getSourceRange(); + } + } + + if (!DiagnosedMixedDesignator && + !isa<DesignatedInitExpr>(InitArgList[0])) { + DiagnosedMixedDesignator = true; + Diag(DIE->getBeginLoc(), diag::ext_designated_init_mixed) + << DIE->getSourceRange(); + Diag(InitArgList[0]->getBeginLoc(), diag::note_designated_init_mixed) + << InitArgList[0]->getSourceRange(); + } + } else if (getLangOpts().CPlusPlus && !DiagnosedMixedDesignator && + isa<DesignatedInitExpr>(InitArgList[0])) { + DiagnosedMixedDesignator = true; + auto *DIE = cast<DesignatedInitExpr>(InitArgList[0]); + Diag(DIE->getBeginLoc(), diag::ext_designated_init_mixed) + << DIE->getSourceRange(); + Diag(InitArgList[I]->getBeginLoc(), diag::note_designated_init_mixed) + << InitArgList[I]->getSourceRange(); + } + } + + if (FirstDesignator.isValid()) { + // Only diagnose designated initiaization as a C++20 extension if we didn't + // already diagnose use of (non-C++20) C99 designator syntax. + if (getLangOpts().CPlusPlus && !DiagnosedArrayDesignator && + !DiagnosedNestedDesignator && !DiagnosedMixedDesignator) { + Diag(FirstDesignator, getLangOpts().CPlusPlus2a + ? diag::warn_cxx17_compat_designated_init + : diag::ext_cxx_designated_init); + } else if (!getLangOpts().CPlusPlus && !getLangOpts().C99) { + Diag(FirstDesignator, diag::ext_designated_init); + } + } + + return BuildInitList(LBraceLoc, InitArgList, RBraceLoc); +} + +ExprResult +Sema::BuildInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, + SourceLocation RBraceLoc) { + // Semantic analysis for initializers is done by ActOnDeclarator() and + // CheckInitializer() - it requires knowledge of the object being initialized. + // Immediately handle non-overload placeholders. Overloads can be // resolved contextually, but everything else here can't. for (unsigned I = 0, E = InitArgList.size(); I != E; ++I) { @@ -6117,9 +6231,6 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, } } - // Semantic analysis for initializers is done by ActOnDeclarator() and - // CheckInitializer() - it requires knowledge of the object being initialized. - InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitArgList, RBraceLoc); E->setType(Context.VoidTy); // FIXME: just a place holder for now. @@ -6422,8 +6533,28 @@ bool Sema::areLaxCompatibleVectorTypes(QualType srcTy, QualType destTy) { bool Sema::isLaxVectorConversion(QualType srcTy, QualType destTy) { assert(destTy->isVectorType() || srcTy->isVectorType()); - if (!Context.getLangOpts().LaxVectorConversions) + switch (Context.getLangOpts().getLaxVectorConversions()) { + case LangOptions::LaxVectorConversionKind::None: return false; + + case LangOptions::LaxVectorConversionKind::Integer: + if (!srcTy->isIntegralOrEnumerationType()) { + auto *Vec = srcTy->getAs<VectorType>(); + if (!Vec || !Vec->getElementType()->isIntegralOrEnumerationType()) + return false; + } + if (!destTy->isIntegralOrEnumerationType()) { + auto *Vec = destTy->getAs<VectorType>(); + if (!Vec || !Vec->getElementType()->isIntegralOrEnumerationType()) + return false; + } + // OK, integer (vector) -> integer (vector) bitcast. + break; + + case LangOptions::LaxVectorConversionKind::All: + break; + } + return areLaxCompatibleVectorTypes(srcTy, destTy); } @@ -6616,8 +6747,8 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, assert(Ty->isVectorType() && "Expected vector type"); SmallVector<Expr *, 8> initExprs; - const VectorType *VTy = Ty->getAs<VectorType>(); - unsigned numElems = Ty->getAs<VectorType>()->getNumElements(); + const VectorType *VTy = Ty->castAs<VectorType>(); + unsigned numElems = VTy->getNumElements(); // '(...)' form of vector initialization in AltiVec: the number of // initializers must be one or must match the size of the vector. @@ -6628,7 +6759,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, // vector. If a single value is specified in the initializer then it will // be replicated to all the components of the vector if (numExprs == 1) { - QualType ElemTy = Ty->getAs<VectorType>()->getElementType(); + QualType ElemTy = VTy->getElementType(); ExprResult Literal = DefaultLvalueConversion(exprs[0]); if (Literal.isInvalid()) return ExprError(); @@ -6650,7 +6781,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, if (getLangOpts().OpenCL && VTy->getVectorKind() == VectorType::GenericVector && numExprs == 1) { - QualType ElemTy = Ty->getAs<VectorType>()->getElementType(); + QualType ElemTy = VTy->getElementType(); ExprResult Literal = DefaultLvalueConversion(exprs[0]); if (Literal.isInvalid()) return ExprError(); @@ -6949,8 +7080,8 @@ checkConditionalObjectPointersCompatibility(Sema &S, ExprResult &LHS, QualType RHSTy = RHS.get()->getType(); // get the "pointed to" types - QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType(); - QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType(); + QualType lhptee = LHSTy->castAs<PointerType>()->getPointeeType(); + QualType rhptee = RHSTy->castAs<PointerType>()->getPointeeType(); // ignore qualifiers on void (C99 6.5.15p3, clause 6) if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) { @@ -7400,9 +7531,10 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, compositeType = RHSOPT->isObjCBuiltinType() ? RHSTy : LHSTy; } else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) { compositeType = LHSOPT->isObjCBuiltinType() ? LHSTy : RHSTy; - } else if ((LHSTy->isObjCQualifiedIdType() || - RHSTy->isObjCQualifiedIdType()) && - Context.ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) { + } else if ((LHSOPT->isObjCQualifiedIdType() || + RHSOPT->isObjCQualifiedIdType()) && + Context.ObjCQualifiedIdTypesAreCompatible(LHSOPT, RHSOPT, + true)) { // Need to handle "id<xx>" explicitly. // GCC allows qualified id and any Objective-C type to devolve to // id. Currently localizing to here until clear this should be @@ -7434,8 +7566,8 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, LHS = RHS = true; return QualType(); } - QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType(); - QualType rhptee = RHSTy->getAs<ObjCObjectPointerType>()->getPointeeType(); + QualType lhptee = LHSTy->castAs<PointerType>()->getPointeeType(); + QualType rhptee = RHSTy->castAs<ObjCObjectPointerType>()->getPointeeType(); QualType destPointee = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); @@ -7454,8 +7586,8 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, LHS = RHS = true; return QualType(); } - QualType lhptee = LHSTy->getAs<ObjCObjectPointerType>()->getPointeeType(); - QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType(); + QualType lhptee = LHSTy->castAs<ObjCObjectPointerType>()->getPointeeType(); + QualType rhptee = RHSTy->castAs<PointerType>()->getPointeeType(); QualType destPointee = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); @@ -7488,7 +7620,12 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc, static bool IsArithmeticOp(BinaryOperatorKind Opc) { return BinaryOperator::isAdditiveOp(Opc) || BinaryOperator::isMultiplicativeOp(Opc) || - BinaryOperator::isShiftOp(Opc); + BinaryOperator::isShiftOp(Opc) || Opc == BO_And || Opc == BO_Or; + // This only checks for bitwise-or and bitwise-and, but not bitwise-xor and + // not any of the logical operators. Bitwise-xor is commonly used as a + // logical-xor because there is no logical-xor operator. The logical + // operators, including uses of xor, have a high false positive rate for + // precedence warnings. } /// IsArithmeticBinaryExpr - Returns true if E is an arithmetic binary @@ -7578,7 +7715,11 @@ static void DiagnoseConditionalPrecedence(Sema &Self, // The condition is an arithmetic binary expression, with a right- // hand side that looks boolean, so warn. - Self.Diag(OpLoc, diag::warn_precedence_conditional) + unsigned DiagID = BinaryOperator::isBitwiseOp(CondOpcode) + ? diag::warn_precedence_bitwise_conditional + : diag::warn_precedence_conditional; + + Self.Diag(OpLoc, DiagID) << Condition->getSourceRange() << BinaryOperator::getOpcodeStr(CondOpcode); @@ -7960,8 +8101,8 @@ checkObjCPointerTypesForAssignment(Sema &S, QualType LHSType, return Sema::IncompatiblePointer; return Sema::Compatible; } - QualType lhptee = LHSType->getAs<ObjCObjectPointerType>()->getPointeeType(); - QualType rhptee = RHSType->getAs<ObjCObjectPointerType>()->getPointeeType(); + QualType lhptee = LHSType->castAs<ObjCObjectPointerType>()->getPointeeType(); + QualType rhptee = RHSType->castAs<ObjCObjectPointerType>()->getPointeeType(); if (!lhptee.isAtLeastAsQualifiedAs(rhptee) && // make an exception for id<P> @@ -9063,7 +9204,7 @@ static void checkArithmeticNull(Sema &S, ExprResult &LHS, ExprResult &RHS, << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); } -static void DiagnoseDivisionSizeofPointer(Sema &S, Expr *LHS, Expr *RHS, +static void DiagnoseDivisionSizeofPointerOrArray(Sema &S, Expr *LHS, Expr *RHS, SourceLocation Loc) { const auto *LUE = dyn_cast<UnaryExprOrTypeTraitExpr>(LHS); const auto *RUE = dyn_cast<UnaryExprOrTypeTraitExpr>(RHS); @@ -9073,7 +9214,8 @@ static void DiagnoseDivisionSizeofPointer(Sema &S, Expr *LHS, Expr *RHS, RUE->getKind() != UETT_SizeOf) return; - QualType LHSTy = LUE->getArgumentExpr()->IgnoreParens()->getType(); + const Expr *LHSArg = LUE->getArgumentExpr()->IgnoreParens(); + QualType LHSTy = LHSArg->getType(); QualType RHSTy; if (RUE->isArgumentType()) @@ -9081,12 +9223,33 @@ static void DiagnoseDivisionSizeofPointer(Sema &S, Expr *LHS, Expr *RHS, else RHSTy = RUE->getArgumentExpr()->IgnoreParens()->getType(); - if (!LHSTy->isPointerType() || RHSTy->isPointerType()) - return; - if (LHSTy->getPointeeType() != RHSTy) - return; + if (LHSTy->isPointerType() && !RHSTy->isPointerType()) { + if (!S.Context.hasSameUnqualifiedType(LHSTy->getPointeeType(), RHSTy)) + return; - S.Diag(Loc, diag::warn_division_sizeof_ptr) << LHS << LHS->getSourceRange(); + S.Diag(Loc, diag::warn_division_sizeof_ptr) << LHS << LHS->getSourceRange(); + if (const auto *DRE = dyn_cast<DeclRefExpr>(LHSArg)) { + if (const ValueDecl *LHSArgDecl = DRE->getDecl()) + S.Diag(LHSArgDecl->getLocation(), diag::note_pointer_declared_here) + << LHSArgDecl; + } + } else if (const auto *ArrayTy = S.Context.getAsArrayType(LHSTy)) { + QualType ArrayElemTy = ArrayTy->getElementType(); + if (ArrayElemTy != S.Context.getBaseElementType(ArrayTy) || + ArrayElemTy->isDependentType() || RHSTy->isDependentType() || + ArrayElemTy->isCharType() || + S.Context.getTypeSize(ArrayElemTy) == S.Context.getTypeSize(RHSTy)) + return; + S.Diag(Loc, diag::warn_division_sizeof_array) + << LHSArg->getSourceRange() << ArrayElemTy << RHSTy; + if (const auto *DRE = dyn_cast<DeclRefExpr>(LHSArg)) { + if (const ValueDecl *LHSArgDecl = DRE->getDecl()) + S.Diag(LHSArgDecl->getLocation(), diag::note_array_declared_here) + << LHSArgDecl; + } + + S.Diag(Loc, diag::note_precedence_silence) << RHS; + } } static void DiagnoseBadDivideOrRemainderValues(Sema& S, ExprResult &LHS, @@ -9122,7 +9285,7 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS, return InvalidOperands(Loc, LHS, RHS); if (IsDiv) { DiagnoseBadDivideOrRemainderValues(*this, LHS, RHS, Loc, IsDiv); - DiagnoseDivisionSizeofPointer(*this, LHS.get(), RHS.get(), Loc); + DiagnoseDivisionSizeofPointerOrArray(*this, LHS.get(), RHS.get(), Loc); } return compType; } @@ -9281,8 +9444,8 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc, // if both are pointers check if operation is valid wrt address spaces if (S.getLangOpts().OpenCL && isLHSPointer && isRHSPointer) { - const PointerType *lhsPtr = LHSExpr->getType()->getAs<PointerType>(); - const PointerType *rhsPtr = RHSExpr->getType()->getAs<PointerType>(); + const PointerType *lhsPtr = LHSExpr->getType()->castAs<PointerType>(); + const PointerType *rhsPtr = RHSExpr->getType()->castAs<PointerType>(); if (!lhsPtr->isAddressSpaceOverlapping(*rhsPtr)) { S.Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) @@ -9914,8 +10077,8 @@ static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc, QualType T = S.FindCompositePointerType(Loc, LHS, RHS); if (T.isNull()) { - if ((LHSType->isPointerType() || LHSType->isMemberPointerType()) && - (RHSType->isPointerType() || RHSType->isMemberPointerType())) + if ((LHSType->isAnyPointerType() || LHSType->isMemberPointerType()) && + (RHSType->isAnyPointerType() || RHSType->isMemberPointerType())) diagnoseDistinctPointerComparison(S, Loc, LHS, RHS, /*isError*/true); else S.InvalidOperands(Loc, LHS, RHS); @@ -10129,20 +10292,18 @@ static void diagnoseLogicalNotOnLHSofCheck(Sema &S, ExprResult &LHS, << FixItHint::CreateInsertion(SecondClose, ")"); } -// Get the decl for a simple expression: a reference to a variable, -// an implicit C++ field reference, or an implicit ObjC ivar reference. -static ValueDecl *getCompareDecl(Expr *E) { - if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) - return DR->getDecl(); - if (ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E)) { - if (Ivar->isFreeIvar()) - return Ivar->getDecl(); - } - if (MemberExpr *Mem = dyn_cast<MemberExpr>(E)) { +// Returns true if E refers to a non-weak array. +static bool checkForArray(const Expr *E) { + const ValueDecl *D = nullptr; + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) { + D = DR->getDecl(); + } else if (const MemberExpr *Mem = dyn_cast<MemberExpr>(E)) { if (Mem->isImplicitAccess()) - return Mem->getMemberDecl(); + D = Mem->getMemberDecl(); } - return nullptr; + if (!D) + return false; + return D->getType()->isArrayType() && !D->isWeak(); } /// Diagnose some forms of syntactically-obvious tautological comparison. @@ -10175,47 +10336,54 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, // obvious cases in the definition of the template anyways. The idea is to // warn when the typed comparison operator will always evaluate to the same // result. - ValueDecl *DL = getCompareDecl(LHSStripped); - ValueDecl *DR = getCompareDecl(RHSStripped); - if (DL && DR && declaresSameEntity(DL, DR)) { - StringRef Result; + + // Used for indexing into %select in warn_comparison_always + enum { + AlwaysConstant, + AlwaysTrue, + AlwaysFalse, + 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 = "true"; + Result = AlwaysTrue; break; case BO_NE: case BO_LT: case BO_GT: - Result = "false"; + Result = AlwaysFalse; break; case BO_Cmp: - Result = "'std::strong_ordering::equal'"; + Result = AlwaysEqual; break; default: + Result = AlwaysConstant; break; } S.DiagRuntimeBehavior(Loc, nullptr, S.PDiag(diag::warn_comparison_always) - << 0 /*self-comparison*/ << !Result.empty() + << 0 /*self-comparison*/ << Result); - } else if (DL && DR && - DL->getType()->isArrayType() && DR->getType()->isArrayType() && - !DL->isWeak() && !DR->isWeak()) { + } else if (checkForArray(LHSStripped) && checkForArray(RHSStripped)) { // What is it always going to evaluate to? - StringRef Result; + unsigned Result; switch(Opc) { case BO_EQ: // e.g. array1 == array2 - Result = "false"; + Result = AlwaysFalse; break; case BO_NE: // e.g. array1 != array2 - Result = "true"; + 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.empty() << Result); + << Result); } if (isa<CastExpr>(LHSStripped)) @@ -10370,7 +10538,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S, return QualType(); } QualType IntType = - LHSStrippedType->getAs<EnumType>()->getDecl()->getIntegerType(); + LHSStrippedType->castAs<EnumType>()->getDecl()->getIntegerType(); assert(IntType->isArithmeticType()); // We can't use `CK_IntegralCast` when the underlying type is 'bool', so we @@ -10446,6 +10614,32 @@ static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS, return S.Context.getLogicalOperationType(); } +void Sema::CheckPtrComparisonWithNullChar(ExprResult &E, ExprResult &NullE) { + if (!NullE.get()->getType()->isAnyPointerType()) + return; + int NullValue = PP.isMacroDefined("NULL") ? 0 : 1; + if (!E.get()->getType()->isAnyPointerType() && + E.get()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNotNull) == + Expr::NPCK_ZeroExpression) { + if (const auto *CL = dyn_cast<CharacterLiteral>(E.get())) { + if (CL->getValue() == 0) + Diag(E.get()->getExprLoc(), diag::warn_pointer_compare) + << NullValue + << FixItHint::CreateReplacement(E.get()->getExprLoc(), + NullValue ? "NULL" : "(void *)0"); + } else if (const auto *CE = dyn_cast<CStyleCastExpr>(E.get())) { + TypeSourceInfo *TI = CE->getTypeInfoAsWritten(); + QualType T = Context.getCanonicalType(TI->getType()).getUnqualifiedType(); + if (T == Context.CharTy) + Diag(E.get()->getExprLoc(), diag::warn_pointer_compare) + << NullValue + << FixItHint::CreateReplacement(E.get()->getExprLoc(), + NullValue ? "NULL" : "(void *)0"); + } + } +} + // C99 6.5.8, C++ [expr.rel] QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, @@ -10479,6 +10673,10 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, } checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/true); + if (!getLangOpts().CPlusPlus && BinaryOperator::isEqualityOp(Opc)) { + CheckPtrComparisonWithNullChar(LHS, RHS); + CheckPtrComparisonWithNullChar(RHS, LHS); + } // Handle vector comparisons separately. if (LHS.get()->getType()->isVectorType() || @@ -10623,8 +10821,8 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, if (LCanPointeeTy != RCanPointeeTy) { // Treat NULL constant as a special case in OpenCL. if (getLangOpts().OpenCL && !LHSIsNull && !RHSIsNull) { - const PointerType *LHSPtr = LHSType->getAs<PointerType>(); - if (!LHSPtr->isAddressSpaceOverlapping(*RHSType->getAs<PointerType>())) { + const PointerType *LHSPtr = LHSType->castAs<PointerType>(); + if (!LHSPtr->isAddressSpaceOverlapping(*RHSType->castAs<PointerType>())) { Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) << LHSType << RHSType << 0 /* comparison */ @@ -10889,7 +11087,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // the largest type to the smallest type to avoid cases where long long == long, // where long gets picked over long long. QualType Sema::GetSignedVectorType(QualType V) { - const VectorType *VTy = V->getAs<VectorType>(); + const VectorType *VTy = V->castAs<VectorType>(); unsigned TypeSize = Context.getTypeSize(VTy->getElementType()); if (isa<ExtVectorType>(VTy)) { @@ -10944,7 +11142,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, // If AltiVec, the comparison results in a numeric type, i.e. // bool for C++, int for C if (getLangOpts().AltiVec && - vType->getAs<VectorType>()->getVectorKind() == VectorType::AltiVecVector) + vType->castAs<VectorType>()->getVectorKind() == VectorType::AltiVecVector) return Context.getLogicalOperationType(); // For non-floating point types, check for self-comparisons of the form @@ -10963,6 +11161,120 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, return GetSignedVectorType(vType); } +static void diagnoseXorMisusedAsPow(Sema &S, const ExprResult &XorLHS, + const ExprResult &XorRHS, + const SourceLocation Loc) { + // Do not diagnose macros. + if (Loc.isMacroID()) + return; + + bool Negative = false; + bool ExplicitPlus = false; + const auto *LHSInt = dyn_cast<IntegerLiteral>(XorLHS.get()); + const auto *RHSInt = dyn_cast<IntegerLiteral>(XorRHS.get()); + + if (!LHSInt) + return; + if (!RHSInt) { + // Check negative literals. + if (const auto *UO = dyn_cast<UnaryOperator>(XorRHS.get())) { + UnaryOperatorKind Opc = UO->getOpcode(); + if (Opc != UO_Minus && Opc != UO_Plus) + return; + RHSInt = dyn_cast<IntegerLiteral>(UO->getSubExpr()); + if (!RHSInt) + return; + Negative = (Opc == UO_Minus); + ExplicitPlus = !Negative; + } else { + return; + } + } + + const llvm::APInt &LeftSideValue = LHSInt->getValue(); + llvm::APInt RightSideValue = RHSInt->getValue(); + if (LeftSideValue != 2 && LeftSideValue != 10) + return; + + if (LeftSideValue.getBitWidth() != RightSideValue.getBitWidth()) + return; + + CharSourceRange ExprRange = CharSourceRange::getCharRange( + LHSInt->getBeginLoc(), S.getLocForEndOfToken(RHSInt->getLocation())); + llvm::StringRef ExprStr = + Lexer::getSourceText(ExprRange, S.getSourceManager(), S.getLangOpts()); + + CharSourceRange XorRange = + CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc)); + llvm::StringRef XorStr = + Lexer::getSourceText(XorRange, S.getSourceManager(), S.getLangOpts()); + // Do not diagnose if xor keyword/macro is used. + if (XorStr == "xor") + return; + + std::string LHSStr = Lexer::getSourceText( + CharSourceRange::getTokenRange(LHSInt->getSourceRange()), + S.getSourceManager(), S.getLangOpts()); + std::string RHSStr = Lexer::getSourceText( + CharSourceRange::getTokenRange(RHSInt->getSourceRange()), + S.getSourceManager(), S.getLangOpts()); + + if (Negative) { + RightSideValue = -RightSideValue; + RHSStr = "-" + RHSStr; + } else if (ExplicitPlus) { + RHSStr = "+" + RHSStr; + } + + StringRef LHSStrRef = LHSStr; + StringRef RHSStrRef = RHSStr; + // Do not diagnose literals with digit separators, binary, hexadecimal, octal + // literals. + if (LHSStrRef.startswith("0b") || LHSStrRef.startswith("0B") || + RHSStrRef.startswith("0b") || RHSStrRef.startswith("0B") || + LHSStrRef.startswith("0x") || LHSStrRef.startswith("0X") || + RHSStrRef.startswith("0x") || RHSStrRef.startswith("0X") || + (LHSStrRef.size() > 1 && LHSStrRef.startswith("0")) || + (RHSStrRef.size() > 1 && RHSStrRef.startswith("0")) || + LHSStrRef.find('\'') != StringRef::npos || + RHSStrRef.find('\'') != StringRef::npos) + return; + + bool SuggestXor = S.getLangOpts().CPlusPlus || S.getPreprocessor().isMacroDefined("xor"); + const llvm::APInt XorValue = LeftSideValue ^ RightSideValue; + int64_t RightSideIntValue = RightSideValue.getSExtValue(); + if (LeftSideValue == 2 && RightSideIntValue >= 0) { + std::string SuggestedExpr = "1 << " + RHSStr; + bool Overflow = false; + llvm::APInt One = (LeftSideValue - 1); + llvm::APInt PowValue = One.sshl_ov(RightSideValue, Overflow); + if (Overflow) { + if (RightSideIntValue < 64) + S.Diag(Loc, diag::warn_xor_used_as_pow_base) + << ExprStr << XorValue.toString(10, true) << ("1LL << " + RHSStr) + << FixItHint::CreateReplacement(ExprRange, "1LL << " + RHSStr); + else if (RightSideIntValue == 64) + S.Diag(Loc, diag::warn_xor_used_as_pow) << ExprStr << XorValue.toString(10, true); + else + return; + } else { + S.Diag(Loc, diag::warn_xor_used_as_pow_base_extra) + << ExprStr << XorValue.toString(10, true) << SuggestedExpr + << PowValue.toString(10, true) + << FixItHint::CreateReplacement( + ExprRange, (RightSideIntValue == 0) ? "1" : SuggestedExpr); + } + + S.Diag(Loc, diag::note_xor_used_as_pow_silence) << ("0x2 ^ " + RHSStr) << SuggestXor; + } else if (LeftSideValue == 10) { + std::string SuggestedValue = "1e" + std::to_string(RightSideIntValue); + S.Diag(Loc, diag::warn_xor_used_as_pow_base) + << ExprStr << XorValue.toString(10, true) << SuggestedValue + << FixItHint::CreateReplacement(ExprRange, SuggestedValue); + S.Diag(Loc, diag::note_xor_used_as_pow_silence) << ("0xA ^ " + RHSStr) << SuggestXor; + } +} + QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc) { // Ensure that either both operands are of the same vector type, or @@ -11014,6 +11326,9 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS, LHS = LHSResult.get(); RHS = RHSResult.get(); + if (Opc == BO_Xor) + diagnoseXorMisusedAsPow(*this, LHS, RHS, Loc); + if (!compType.isNull() && compType->isIntegralOrUnscopedEnumerationType()) return compType; return InvalidOperands(Loc, LHS, RHS); @@ -11027,10 +11342,22 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS, if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) return CheckVectorLogicalOperands(LHS, RHS, Loc); + bool EnumConstantInBoolContext = false; + for (const ExprResult &HS : {LHS, RHS}) { + if (const auto *DREHS = dyn_cast<DeclRefExpr>(HS.get())) { + const auto *ECDHS = dyn_cast<EnumConstantDecl>(DREHS->getDecl()); + if (ECDHS && ECDHS->getInitVal() != 0 && ECDHS->getInitVal() != 1) + EnumConstantInBoolContext = true; + } + } + + if (EnumConstantInBoolContext) + Diag(Loc, diag::warn_enum_constant_in_bool_context); + // Diagnose cases where the user write a logical and/or but probably meant a // bitwise one. We do this when the LHS is a non-bool integer and the RHS // is a constant. - if (LHS.get()->getType()->isIntegerType() && + if (!EnumConstantInBoolContext && LHS.get()->getType()->isIntegerType() && !LHS.get()->getType()->isBooleanType() && RHS.get()->getType()->isIntegerType() && !RHS.get()->isValueDependent() && // Don't warn in macros or template instantiations. @@ -11651,6 +11978,21 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, CheckForNullPointerDereference(*this, LHSExpr); + if (getLangOpts().CPlusPlus2a && LHSType.isVolatileQualified()) { + if (CompoundType.isNull()) { + // C++2a [expr.ass]p5: + // A simple-assignment whose left operand is of a volatile-qualified + // type is deprecated unless the assignment is either a discarded-value + // expression or an unevaluated operand + ExprEvalContexts.back().VolatileAssignmentLHSs.push_back(LHSExpr); + } else { + // C++2a [expr.ass]p6: + // [Compound-assignment] expressions are deprecated if E1 has + // volatile-qualified type + Diag(Loc, diag::warn_deprecated_compound_assign_volatile) << LHSType; + } + } + // C99 6.5.16p3: The type of an assignment expression is the type of the // left operand unless the left operand has qualified type, in which case // it is the unqualified version of the type of the left operand. @@ -11824,11 +12166,11 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, } else if (S.getLangOpts().AltiVec && ResType->isVectorType()) { // OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 ) } else if (S.getLangOpts().ZVector && ResType->isVectorType() && - (ResType->getAs<VectorType>()->getVectorKind() != + (ResType->castAs<VectorType>()->getVectorKind() != VectorType::AltiVecBool)) { // The z vector extensions allow ++ and -- for non-bool vectors. } else if(S.getLangOpts().OpenCL && ResType->isVectorType() && - ResType->getAs<VectorType>()->getElementType()->isIntegerType()) { + ResType->castAs<VectorType>()->getElementType()->isIntegerType()) { // OpenCL V1.2 6.3 says dec/inc ops operate on integer vector types. } else { S.Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement) @@ -11839,6 +12181,12 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, // Now make sure the operand is a modifiable lvalue. if (CheckForModifiableLvalue(Op, OpLoc, S)) return QualType(); + if (S.getLangOpts().CPlusPlus2a && ResType.isVolatileQualified()) { + // C++2a [expr.pre.inc]p1, [expr.post.inc]p1: + // An operand with volatile-qualified type is deprecated + S.Diag(OpLoc, diag::warn_deprecated_increment_decrement_volatile) + << IsInc << ResType; + } // In C++, a prefix increment is the same type as the operand. Otherwise // (in C or with postfix), the increment is the unqualified type of the // operand. @@ -12414,7 +12762,7 @@ static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS, LHS = convertVector(LHS.get(), Context.FloatTy, S); auto *BO = new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, BinOpResTy, VK, OK, OpLoc, FPFeatures); - return convertVector(BO, ResultTy->getAs<VectorType>()->getElementType(), S); + return convertVector(BO, ResultTy->castAs<VectorType>()->getElementType(), S); } static std::pair<ExprResult, ExprResult> @@ -12971,6 +13319,13 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc, S.LookupOverloadedOperatorName(OverOp, Sc, LHS->getType(), RHS->getType(), Functions); + // In C++20 onwards, we may have a second operator to look up. + if (S.getLangOpts().CPlusPlus2a) { + if (OverloadedOperatorKind ExtraOp = getRewrittenOverloadedOperator(OverOp)) + S.LookupOverloadedOperatorName(ExtraOp, Sc, LHS->getType(), + RHS->getType(), Functions); + } + // Build the (potentially-overloaded, potentially-dependent) // binary operation. return S.CreateOverloadedBinOp(OpLoc, Opc, Functions, LHS, RHS); @@ -13170,7 +13525,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, else if (resultType->isVectorType() && // The z vector extensions don't allow + or - with bool vectors. (!Context.getLangOpts().ZVector || - resultType->getAs<VectorType>()->getVectorKind() != + resultType->castAs<VectorType>()->getVectorKind() != VectorType::AltiVecBool)) break; else if (getLangOpts().CPlusPlus && // C++ [expr.unary.op]p6 @@ -13186,7 +13541,6 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, if (Input.isInvalid()) return ExprError(); resultType = Input.get()->getType(); - if (resultType->isDependentType()) break; // C99 6.5.3.3p1. We allow complex int and float as a GCC extension. @@ -13199,7 +13553,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, else if (resultType->isExtVectorType() && Context.getLangOpts().OpenCL) { // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate // on vector float types. - QualType T = resultType->getAs<ExtVectorType>()->getElementType(); + QualType T = resultType->castAs<ExtVectorType>()->getElementType(); if (!T->isIntegerType()) return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); @@ -13244,7 +13598,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, !Context.getLangOpts().OpenCLCPlusPlus) { // OpenCL v1.1 6.3.h: The logical operator not (!) does not // operate on vector float types. - QualType T = resultType->getAs<ExtVectorType>()->getElementType(); + QualType T = resultType->castAs<ExtVectorType>()->getElementType(); if (!T->isIntegerType()) return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); @@ -13728,10 +14082,11 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) { BlockDecl *Block = BlockDecl::Create(Context, CurContext, CaretLoc); if (LangOpts.CPlusPlus) { + MangleNumberingContext *MCtx; Decl *ManglingContextDecl; - if (MangleNumberingContext *MCtx = - getCurrentMangleNumberContext(Block->getDeclContext(), - ManglingContextDecl)) { + std::tie(MCtx, ManglingContextDecl) = + getCurrentMangleNumberContext(Block->getDeclContext()); + if (MCtx) { unsigned ManglingNumber = MCtx->getManglingNumber(Block); Block->setBlockMangling(ManglingNumber, ManglingContextDecl); } @@ -13909,7 +14264,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, // If the user wrote a function type in some form, try to use that. if (!BSI->FunctionType.isNull()) { - const FunctionType *FTy = BSI->FunctionType->getAs<FunctionType>(); + const FunctionType *FTy = BSI->FunctionType->castAs<FunctionType>(); FunctionType::ExtInfo Ext = FTy->getExtInfo(); if (NoReturn && !Ext.getNoReturn()) Ext = Ext.withNoReturn(true); @@ -14381,24 +14736,24 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, case IncompatibleObjCQualifiedId: { if (SrcType->isObjCQualifiedIdType()) { const ObjCObjectPointerType *srcOPT = - SrcType->getAs<ObjCObjectPointerType>(); + SrcType->castAs<ObjCObjectPointerType>(); for (auto *srcProto : srcOPT->quals()) { PDecl = srcProto; break; } if (const ObjCInterfaceType *IFaceT = - DstType->getAs<ObjCObjectPointerType>()->getInterfaceType()) + DstType->castAs<ObjCObjectPointerType>()->getInterfaceType()) IFace = IFaceT->getDecl(); } else if (DstType->isObjCQualifiedIdType()) { const ObjCObjectPointerType *dstOPT = - DstType->getAs<ObjCObjectPointerType>(); + DstType->castAs<ObjCObjectPointerType>(); for (auto *dstProto : dstOPT->quals()) { PDecl = dstProto; break; } if (const ObjCInterfaceType *IFaceT = - SrcType->getAs<ObjCObjectPointerType>()->getInterfaceType()) + SrcType->castAs<ObjCObjectPointerType>()->getInterfaceType()) IFace = IFaceT->getDecl(); } DiagKind = diag::warn_incompatible_qualified_id; @@ -14775,6 +15130,26 @@ void Sema::WarnOnPendingNoDerefs(ExpressionEvaluationContextRecord &Rec) { Rec.PossibleDerefs.clear(); } +/// Check whether E, which is either a discarded-value expression or an +/// unevaluated operand, is a simple-assignment to a volatlie-qualified lvalue, +/// and if so, remove it from the list of volatile-qualified assignments that +/// we are going to warn are deprecated. +void Sema::CheckUnusedVolatileAssignment(Expr *E) { + if (!E->getType().isVolatileQualified() || !getLangOpts().CPlusPlus2a) + return; + + // Note: ignoring parens here is not justified by the standard rules, but + // ignoring parentheses seems like a more reasonable approach, and this only + // drives a deprecation warning so doesn't affect conformance. + if (auto *BO = dyn_cast<BinaryOperator>(E->IgnoreParenImpCasts())) { + if (BO->getOpcode() == BO_Assign) { + auto &LHSs = ExprEvalContexts.back().VolatileAssignmentLHSs; + LHSs.erase(std::remove(LHSs.begin(), LHSs.end(), BO->getLHS()), + LHSs.end()); + } + } +} + void Sema::PopExpressionEvaluationContext() { ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back(); unsigned NumTypos = Rec.NumTypos; @@ -14809,6 +15184,13 @@ void Sema::PopExpressionEvaluationContext() { WarnOnPendingNoDerefs(Rec); + // Warn on any volatile-qualified simple-assignments that are not discarded- + // value expressions nor unevaluated operands (those cases get removed from + // this list by CheckUnusedVolatileAssignment). + for (auto *BO : Rec.VolatileAssignmentLHSs) + Diag(BO->getBeginLoc(), diag::warn_deprecated_simple_assign_volatile) + << BO->getType(); + // When are coming out of an unevaluated context, clear out any // temporaries that we may have created as part of the evaluation of // the expression in that context: they aren't relevant because they @@ -15032,6 +15414,17 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, if (IsRecursiveCall && OdrUse == OdrUseContext::Used) OdrUse = OdrUseContext::FormallyOdrUsed; + // Trivial default constructors and destructors are never actually used. + // FIXME: What about other special members? + if (Func->isTrivial() && !Func->hasAttr<DLLExportAttr>() && + OdrUse == OdrUseContext::Used) { + if (auto *Constructor = dyn_cast<CXXConstructorDecl>(Func)) + if (Constructor->isDefaultConstructor()) + OdrUse = OdrUseContext::FormallyOdrUsed; + if (isa<CXXDestructorDecl>(Func)) + OdrUse = OdrUseContext::FormallyOdrUsed; + } + // C++20 [expr.const]p12: // A function [...] is needed for constant evaluation if it is [...] a // constexpr function that is named by an expression that is potentially @@ -15092,98 +15485,101 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // If we need a definition, try to create one. if (NeedDefinition && !Func->getBody()) { - if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) { - Constructor = cast<CXXConstructorDecl>(Constructor->getFirstDecl()); - if (Constructor->isDefaulted() && !Constructor->isDeleted()) { - if (Constructor->isDefaultConstructor()) { - if (Constructor->isTrivial() && - !Constructor->hasAttr<DLLExportAttr>()) + runWithSufficientStackSpace(Loc, [&] { + if (CXXConstructorDecl *Constructor = + dyn_cast<CXXConstructorDecl>(Func)) { + Constructor = cast<CXXConstructorDecl>(Constructor->getFirstDecl()); + if (Constructor->isDefaulted() && !Constructor->isDeleted()) { + if (Constructor->isDefaultConstructor()) { + if (Constructor->isTrivial() && + !Constructor->hasAttr<DLLExportAttr>()) + return; + DefineImplicitDefaultConstructor(Loc, Constructor); + } else if (Constructor->isCopyConstructor()) { + DefineImplicitCopyConstructor(Loc, Constructor); + } else if (Constructor->isMoveConstructor()) { + DefineImplicitMoveConstructor(Loc, Constructor); + } + } else if (Constructor->getInheritedConstructor()) { + DefineInheritingConstructor(Loc, Constructor); + } + } else if (CXXDestructorDecl *Destructor = + dyn_cast<CXXDestructorDecl>(Func)) { + Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl()); + if (Destructor->isDefaulted() && !Destructor->isDeleted()) { + if (Destructor->isTrivial() && !Destructor->hasAttr<DLLExportAttr>()) return; - DefineImplicitDefaultConstructor(Loc, Constructor); - } else if (Constructor->isCopyConstructor()) { - DefineImplicitCopyConstructor(Loc, Constructor); - } else if (Constructor->isMoveConstructor()) { - DefineImplicitMoveConstructor(Loc, Constructor); + DefineImplicitDestructor(Loc, Destructor); } - } else if (Constructor->getInheritedConstructor()) { - DefineInheritingConstructor(Loc, Constructor); - } - } else if (CXXDestructorDecl *Destructor = - dyn_cast<CXXDestructorDecl>(Func)) { - Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl()); - if (Destructor->isDefaulted() && !Destructor->isDeleted()) { - if (Destructor->isTrivial() && !Destructor->hasAttr<DLLExportAttr>()) - return; - DefineImplicitDestructor(Loc, Destructor); + if (Destructor->isVirtual() && getLangOpts().AppleKext) + MarkVTableUsed(Loc, Destructor->getParent()); + } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) { + if (MethodDecl->isOverloadedOperator() && + MethodDecl->getOverloadedOperator() == OO_Equal) { + MethodDecl = cast<CXXMethodDecl>(MethodDecl->getFirstDecl()); + if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) { + if (MethodDecl->isCopyAssignmentOperator()) + DefineImplicitCopyAssignment(Loc, MethodDecl); + else if (MethodDecl->isMoveAssignmentOperator()) + DefineImplicitMoveAssignment(Loc, MethodDecl); + } + } else if (isa<CXXConversionDecl>(MethodDecl) && + MethodDecl->getParent()->isLambda()) { + CXXConversionDecl *Conversion = + cast<CXXConversionDecl>(MethodDecl->getFirstDecl()); + if (Conversion->isLambdaToBlockPointerConversion()) + DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion); + else + DefineImplicitLambdaToFunctionPointerConversion(Loc, Conversion); + } else if (MethodDecl->isVirtual() && getLangOpts().AppleKext) + MarkVTableUsed(Loc, MethodDecl->getParent()); } - if (Destructor->isVirtual() && getLangOpts().AppleKext) - MarkVTableUsed(Loc, Destructor->getParent()); - } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) { - if (MethodDecl->isOverloadedOperator() && - MethodDecl->getOverloadedOperator() == OO_Equal) { - MethodDecl = cast<CXXMethodDecl>(MethodDecl->getFirstDecl()); - if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) { - if (MethodDecl->isCopyAssignmentOperator()) - DefineImplicitCopyAssignment(Loc, MethodDecl); - else if (MethodDecl->isMoveAssignmentOperator()) - DefineImplicitMoveAssignment(Loc, MethodDecl); - } - } else if (isa<CXXConversionDecl>(MethodDecl) && - MethodDecl->getParent()->isLambda()) { - CXXConversionDecl *Conversion = - cast<CXXConversionDecl>(MethodDecl->getFirstDecl()); - if (Conversion->isLambdaToBlockPointerConversion()) - DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion); - else - DefineImplicitLambdaToFunctionPointerConversion(Loc, Conversion); - } else if (MethodDecl->isVirtual() && getLangOpts().AppleKext) - MarkVTableUsed(Loc, MethodDecl->getParent()); - } - // Implicit instantiation of function templates and member functions of - // class templates. - if (Func->isImplicitlyInstantiable()) { - TemplateSpecializationKind TSK = - Func->getTemplateSpecializationKindForInstantiation(); - SourceLocation PointOfInstantiation = Func->getPointOfInstantiation(); - bool FirstInstantiation = PointOfInstantiation.isInvalid(); - if (FirstInstantiation) { - PointOfInstantiation = Loc; - Func->setTemplateSpecializationKind(TSK, PointOfInstantiation); - } else if (TSK != TSK_ImplicitInstantiation) { - // Use the point of use as the point of instantiation, instead of the - // point of explicit instantiation (which we track as the actual point - // of instantiation). This gives better backtraces in diagnostics. - PointOfInstantiation = Loc; - } + // Implicit instantiation of function templates and member functions of + // class templates. + if (Func->isImplicitlyInstantiable()) { + TemplateSpecializationKind TSK = + Func->getTemplateSpecializationKindForInstantiation(); + SourceLocation PointOfInstantiation = Func->getPointOfInstantiation(); + bool FirstInstantiation = PointOfInstantiation.isInvalid(); + if (FirstInstantiation) { + PointOfInstantiation = Loc; + Func->setTemplateSpecializationKind(TSK, PointOfInstantiation); + } else if (TSK != TSK_ImplicitInstantiation) { + // Use the point of use as the point of instantiation, instead of the + // point of explicit instantiation (which we track as the actual point + // of instantiation). This gives better backtraces in diagnostics. + PointOfInstantiation = Loc; + } - if (FirstInstantiation || TSK != TSK_ImplicitInstantiation || - Func->isConstexpr()) { - if (isa<CXXRecordDecl>(Func->getDeclContext()) && - cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() && - CodeSynthesisContexts.size()) - PendingLocalImplicitInstantiations.push_back( - std::make_pair(Func, PointOfInstantiation)); - else if (Func->isConstexpr()) - // Do not defer instantiations of constexpr functions, to avoid the - // expression evaluator needing to call back into Sema if it sees a - // call to such a function. - InstantiateFunctionDefinition(PointOfInstantiation, Func); - else { - Func->setInstantiationIsPending(true); - PendingInstantiations.push_back( - std::make_pair(Func, PointOfInstantiation)); - // Notify the consumer that a function was implicitly instantiated. - Consumer.HandleCXXImplicitFunctionInstantiation(Func); + if (FirstInstantiation || TSK != TSK_ImplicitInstantiation || + Func->isConstexpr()) { + if (isa<CXXRecordDecl>(Func->getDeclContext()) && + cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() && + CodeSynthesisContexts.size()) + PendingLocalImplicitInstantiations.push_back( + std::make_pair(Func, PointOfInstantiation)); + else if (Func->isConstexpr()) + // Do not defer instantiations of constexpr functions, to avoid the + // expression evaluator needing to call back into Sema if it sees a + // call to such a function. + InstantiateFunctionDefinition(PointOfInstantiation, Func); + else { + Func->setInstantiationIsPending(true); + PendingInstantiations.push_back( + std::make_pair(Func, PointOfInstantiation)); + // Notify the consumer that a function was implicitly instantiated. + Consumer.HandleCXXImplicitFunctionInstantiation(Func); + } + } + } else { + // Walk redefinitions, as some of them may be instantiable. + for (auto i : Func->redecls()) { + if (!i->isUsed(false) && i->isImplicitlyInstantiable()) + MarkFunctionReferenced(Loc, i, MightBeOdrUse); } } - } else { - // Walk redefinitions, as some of them may be instantiable. - for (auto i : Func->redecls()) { - if (!i->isUsed(false) && i->isImplicitlyInstantiable()) - MarkFunctionReferenced(Loc, i, MightBeOdrUse); - } - } + }); } // If this is the first "real" use, act on that. @@ -15207,9 +15603,14 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, CheckCompleteParameterTypesForMangler(*this, Func, Loc); Func->markUsed(Context); + } - if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice) + if (LangOpts.OpenMP) { + markOpenMPDeclareVariantFuncsReferenced(Loc, Func, MightBeOdrUse); + if (LangOpts.OpenMPIsDevice) checkOpenMPDeviceFunction(Loc, Func); + else + checkOpenMPHostFunction(Loc, Func); } } @@ -15447,27 +15848,11 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var, // Warn about implicitly autoreleasing indirect parameters captured by blocks. if (const auto *PT = CaptureType->getAs<PointerType>()) { - // This function finds out whether there is an AttributedType of kind - // attr::ObjCOwnership in Ty. The existence of AttributedType of kind - // attr::ObjCOwnership implies __autoreleasing was explicitly specified - // rather than being added implicitly by the compiler. - auto IsObjCOwnershipAttributedType = [](QualType Ty) { - while (const auto *AttrTy = Ty->getAs<AttributedType>()) { - if (AttrTy->getAttrKind() == attr::ObjCOwnership) - return true; - - // Peel off AttributedTypes that are not of kind ObjCOwnership. - Ty = AttrTy->getModifiedType(); - } - - return false; - }; - QualType PointeeTy = PT->getPointeeType(); if (!Invalid && PointeeTy->getAs<ObjCObjectPointerType>() && PointeeTy.getObjCLifetime() == Qualifiers::OCL_Autoreleasing && - !IsObjCOwnershipAttributedType(PointeeTy)) { + !S.Context.hasDirectOwnershipQualifier(PointeeTy)) { if (BuildAndDiagnose) { SourceLocation VarLoc = Var->getLocation(); S.Diag(Loc, diag::warn_block_capture_autoreleasing); @@ -15517,7 +15902,8 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, if (HasConst) DeclRefType.addConst(); } - ByRef = S.isOpenMPCapturedByRef(Var, RSI->OpenMPLevel); + ByRef = S.isOpenMPCapturedByRef(Var, RSI->OpenMPLevel, + RSI->OpenMPCaptureLevel); } if (ByRef) @@ -15745,7 +16131,25 @@ bool Sema::tryCaptureVariable( // target region should not be captured outside the scope of the region. if (RSI->CapRegionKind == CR_OpenMP) { bool IsOpenMPPrivateDecl = isOpenMPPrivateDecl(Var, RSI->OpenMPLevel); - auto IsTargetCap = !IsOpenMPPrivateDecl && + // If the variable is private (i.e. not captured) and has variably + // modified type, we still need to capture the type for correct + // codegen in all regions, associated with the construct. Currently, + // it is captured in the innermost captured region only. + if (IsOpenMPPrivateDecl && Var->getType()->isVariablyModifiedType()) { + QualType QTy = Var->getType(); + if (ParmVarDecl *PVD = dyn_cast_or_null<ParmVarDecl>(Var)) + QTy = PVD->getOriginalType(); + for (int I = 1, E = getNumberOfConstructScopes(RSI->OpenMPLevel); + I < E; ++I) { + auto *OuterRSI = cast<CapturedRegionScopeInfo>( + FunctionScopes[FunctionScopesIndex - I]); + assert(RSI->OpenMPLevel == OuterRSI->OpenMPLevel && + "Wrong number of captured regions associated with the " + "OpenMP construct."); + captureVariablyModifiedType(Context, QTy, OuterRSI); + } + } + bool IsTargetCap = !IsOpenMPPrivateDecl && isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel); // When we detect target captures we are looking from inside the // target region, therefore we need to propagate the capture from the @@ -16354,7 +16758,9 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, if (UsableInConstantExpr) { // Do not defer instantiations of variables that could be used in a // constant expression. - SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var); + SemaRef.runWithSufficientStackSpace(PointOfInstantiation, [&] { + SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var); + }); } else if (FirstInstantiation || isa<VarTemplateSpecializationDecl>(Var)) { // FIXME: For a specialization of a variable template, we don't @@ -17546,6 +17952,9 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ case BuiltinType::Id: #include "clang/Basic/OpenCLExtensionTypes.def" +#define SVE_TYPE(Name, Id, SingletonId) \ + case BuiltinType::Id: +#include "clang/Basic/AArch64SVEACLETypes.def" #define BUILTIN_TYPE(Id, SingletonId) case BuiltinType::Id: #define PLACEHOLDER_TYPE(Id, SingletonId) #include "clang/AST/BuiltinTypes.def" diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 705e3b9bd7fb..9aae9289b514 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -453,6 +453,9 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, if (T->isVariablyModifiedType()) return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid) << T); + if (CheckQualifiedFunctionForTypeId(T, TypeidLoc)) + return ExprError(); + return new (Context) CXXTypeidExpr(TypeInfoType.withConst(), Operand, SourceRange(TypeidLoc, RParenLoc)); } @@ -496,6 +499,11 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, } } + ExprResult Result = CheckUnevaluatedOperand(E); + if (Result.isInvalid()) + return ExprError(); + E = Result.get(); + // C++ [expr.typeid]p4: // [...] If the type of the type-id is a reference to a possibly // cv-qualified type, the result of the typeid expression refers to a @@ -2108,9 +2116,10 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, QualType InitType; if (KnownArraySize) InitType = Context.getConstantArrayType( - AllocType, llvm::APInt(Context.getTypeSize(Context.getSizeType()), - *KnownArraySize), - ArrayType::Normal, 0); + AllocType, + llvm::APInt(Context.getTypeSize(Context.getSizeType()), + *KnownArraySize), + *ArraySize, ArrayType::Normal, 0); else if (ArraySize) InitType = Context.getIncompleteArrayType(AllocType, ArrayType::Normal, 0); @@ -2457,8 +2466,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // deallocation function's name is looked up in the global scope. LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName); if (AllocElemType->isRecordType() && DeleteScope != AFS_Global) { - CXXRecordDecl *RD - = cast<CXXRecordDecl>(AllocElemType->getAs<RecordType>()->getDecl()); + auto *RD = + cast<CXXRecordDecl>(AllocElemType->castAs<RecordType>()->getDecl()); LookupQualifiedName(FoundDelete, RD); } if (FoundDelete.isAmbiguous()) @@ -3293,7 +3302,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // itself in this case. return ExprError(); - QualType Pointee = Type->getAs<PointerType>()->getPointeeType(); + QualType Pointee = Type->castAs<PointerType>()->getPointeeType(); QualType PointeeElem = Context.getBaseElementType(Pointee); if (Pointee.getAddressSpace() != LangAS::Default && @@ -4025,8 +4034,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, case ICK_Complex_Promotion: case ICK_Complex_Conversion: { - QualType FromEl = From->getType()->getAs<ComplexType>()->getElementType(); - QualType ToEl = ToType->getAs<ComplexType>()->getElementType(); + QualType FromEl = From->getType()->castAs<ComplexType>()->getElementType(); + QualType ToEl = ToType->castAs<ComplexType>()->getElementType(); CastKind CK; if (FromEl->isRealFloatingType()) { if (ToEl->isRealFloatingType()) @@ -4605,7 +4614,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, return RD->hasAttr<FinalAttr>(); return false; case UTT_IsSigned: - return T->isSignedIntegerType(); + // Enum types should always return false. + // Floating points should always return true. + return !T->isEnumeralType() && (T->isFloatingType() || T->isSignedIntegerType()); case UTT_IsUnsigned: return T->isUnsignedIntegerType(); @@ -5232,7 +5243,13 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); ExprResult Result = Self.BuildBinOp(/*S=*/nullptr, KeyLoc, BO_Assign, &Lhs, &Rhs); - if (Result.isInvalid() || SFINAE.hasErrorOccurred()) + if (Result.isInvalid()) + return false; + + // Treat the assignment as unused for the purpose of -Wdeprecated-volatile. + Self.CheckUnusedVolatileAssignment(Result.get()); + + if (SFINAE.hasErrorOccurred()) return false; if (BTT == BTT_IsAssignable) @@ -5835,20 +5852,21 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, 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; - if (CompareReferenceRelationship( - QuestionLoc, LTy, RTy, DerivedToBase, - ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible && + bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion, + FunctionConversion; + if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, DerivedToBase, + ObjCConversion, ObjCLifetimeConversion, + FunctionConversion) == Ref_Compatible && !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion && // [...] subject to the constraint that the reference must bind // directly [...] - !RHS.get()->refersToBitField() && - !RHS.get()->refersToVectorElement()) { + !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) == Ref_Compatible && + QuestionLoc, RTy, LTy, DerivedToBase, ObjCConversion, + ObjCLifetimeConversion, + FunctionConversion) == Ref_Compatible && !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion && !LHS.get()->refersToBitField() && !LHS.get()->refersToVectorElement()) { @@ -6603,6 +6621,11 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) { ExprEvalContexts.back().ExprContext = ExpressionEvaluationContextRecord::EK_Other; + Result = CheckUnevaluatedOperand(E); + if (Result.isInvalid()) + return ExprError(); + E = Result.get(); + // In MS mode, don't perform any extra checking of call return types within a // decltype expression. if (getLangOpts().MSVCCompat) @@ -6794,14 +6817,10 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, // it's legal for the type to be incomplete if this is a pseudo-destructor // call. We'll do more incomplete-type checks later in the lookup process, // so just skip this check for ObjC types. - if (BaseType->isObjCObjectOrInterfaceType()) { + if (!BaseType->isRecordType()) { ObjectType = ParsedType::make(BaseType); MayBePseudoDestructor = true; return Base; - } else if (!BaseType->isRecordType()) { - ObjectType = nullptr; - MayBePseudoDestructor = true; - return Base; } // The object type must be complete (or dependent), or @@ -7173,7 +7192,7 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, if (Method->getParent()->isLambda() && Method->getConversionType()->isBlockPointerType()) { - // This is a lambda coversion to block pointer; check if the argument + // This is a lambda conversion to block pointer; check if the argument // was a LambdaExpr. Expr *SubE = E; CastExpr *CE = dyn_cast<CastExpr>(SubE); @@ -7231,7 +7250,10 @@ ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, if (R.isInvalid()) return R; - // The operand may have been modified when checking the placeholder type. + R = CheckUnevaluatedOperand(R.get()); + if (R.isInvalid()) + return ExprError(); + Operand = R.get(); if (!inTemplateInstantiation() && Operand->HasSideEffects(Context, false)) { @@ -7335,12 +7357,17 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) { // volatile lvalue with a special form, we perform an lvalue-to-rvalue // conversion. if (getLangOpts().CPlusPlus11 && E->isGLValue() && - E->getType().isVolatileQualified() && - IsSpecialDiscardedValue(E)) { - ExprResult Res = DefaultLvalueConversion(E); - if (Res.isInvalid()) - return E; - E = Res.get(); + E->getType().isVolatileQualified()) { + if (IsSpecialDiscardedValue(E)) { + ExprResult Res = DefaultLvalueConversion(E); + if (Res.isInvalid()) + return E; + E = Res.get(); + } else { + // Per C++2a [expr.ass]p5, a volatile assignment is not deprecated if + // it occurs as a discarded-value expression. + CheckUnusedVolatileAssignment(E); + } } // C++1z: @@ -7375,6 +7402,14 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) { return E; } +ExprResult Sema::CheckUnevaluatedOperand(Expr *E) { + // Per C++2a [expr.ass]p5, a volatile assignment is not deprecated if + // it occurs as an unevaluated operand. + CheckUnusedVolatileAssignment(E); + + return E; +} + // If we can unambiguously determine whether Var can never be used // in a constant expression, return true. // - if the variable and its initializer are non-dependent, then @@ -7584,15 +7619,22 @@ class TransformTypos : public TreeTransform<TransformTypos> { llvm::SmallDenseMap<OverloadExpr *, Expr *, 4> OverloadResolution; /// Emit diagnostics for all of the TypoExprs encountered. + /// /// If the TypoExprs were successfully corrected, then the diagnostics should /// suggest the corrections. Otherwise the diagnostics will not suggest /// anything (having been passed an empty TypoCorrection). - void EmitAllDiagnostics() { + /// + /// If we've failed to correct due to ambiguous corrections, we need to + /// be sure to pass empty corrections and replacements. Otherwise it's + /// possible that the Consumer has a TypoCorrection that failed to ambiguity + /// and we don't want to report those diagnostics. + void EmitAllDiagnostics(bool IsAmbiguous) { for (TypoExpr *TE : TypoExprs) { auto &State = SemaRef.getTypoExprState(TE); if (State.DiagHandler) { - TypoCorrection TC = State.Consumer->getCurrentCorrection(); - ExprResult Replacement = TransformCache[TE]; + TypoCorrection TC = IsAmbiguous + ? TypoCorrection() : State.Consumer->getCurrentCorrection(); + ExprResult Replacement = IsAmbiguous ? ExprError() : TransformCache[TE]; // Extract the NamedDecl from the transformed TypoExpr and add it to the // TypoCorrection, replacing the existing decls. This ensures the right @@ -7654,6 +7696,149 @@ class TransformTypos : public TreeTransform<TransformTypos> { return ExprFilter(Res.get()); } + // Since correcting typos may intoduce new TypoExprs, this function + // checks for new TypoExprs and recurses if it finds any. Note that it will + // only succeed if it is able to correct all typos in the given expression. + ExprResult CheckForRecursiveTypos(ExprResult Res, bool &IsAmbiguous) { + if (Res.isInvalid()) { + return Res; + } + // Check to see if any new TypoExprs were created. If so, we need to recurse + // to check their validity. + Expr *FixedExpr = Res.get(); + + auto SavedTypoExprs = std::move(TypoExprs); + auto SavedAmbiguousTypoExprs = std::move(AmbiguousTypoExprs); + TypoExprs.clear(); + AmbiguousTypoExprs.clear(); + + FindTypoExprs(TypoExprs).TraverseStmt(FixedExpr); + if (!TypoExprs.empty()) { + // Recurse to handle newly created TypoExprs. If we're not able to + // handle them, discard these TypoExprs. + ExprResult RecurResult = + RecursiveTransformLoop(FixedExpr, IsAmbiguous); + if (RecurResult.isInvalid()) { + Res = ExprError(); + // Recursive corrections didn't work, wipe them away and don't add + // them to the TypoExprs set. Remove them from Sema's TypoExpr list + // since we don't want to clear them twice. Note: it's possible the + // TypoExprs were created recursively and thus won't be in our + // Sema's TypoExprs - they were created in our `RecursiveTransformLoop`. + auto &SemaTypoExprs = SemaRef.TypoExprs; + for (auto TE : TypoExprs) { + TransformCache.erase(TE); + SemaRef.clearDelayedTypo(TE); + + auto SI = find(SemaTypoExprs, TE); + if (SI != SemaTypoExprs.end()) { + SemaTypoExprs.erase(SI); + } + } + } else { + // TypoExpr is valid: add newly created TypoExprs since we were + // able to correct them. + Res = RecurResult; + SavedTypoExprs.set_union(TypoExprs); + } + } + + TypoExprs = std::move(SavedTypoExprs); + AmbiguousTypoExprs = std::move(SavedAmbiguousTypoExprs); + + return Res; + } + + // Try to transform the given expression, looping through the correction + // candidates with `CheckAndAdvanceTypoExprCorrectionStreams`. + // + // If valid ambiguous typo corrections are seen, `IsAmbiguous` is set to + // true and this method immediately will return an `ExprError`. + ExprResult RecursiveTransformLoop(Expr *E, bool &IsAmbiguous) { + ExprResult Res; + auto SavedTypoExprs = std::move(SemaRef.TypoExprs); + SemaRef.TypoExprs.clear(); + + while (true) { + Res = CheckForRecursiveTypos(TryTransform(E), IsAmbiguous); + + // Recursion encountered an ambiguous correction. This means that our + // correction itself is ambiguous, so stop now. + if (IsAmbiguous) + break; + + // If the transform is still valid after checking for any new typos, + // it's good to go. + if (!Res.isInvalid()) + break; + + // The transform was invalid, see if we have any TypoExprs with untried + // correction candidates. + if (!CheckAndAdvanceTypoExprCorrectionStreams()) + break; + } + + // 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(); + // 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()) { + auto TE = AmbiguousTypoExprs.back(); + + // TryTransform itself can create new Typos, adding them to the TypoExpr map + // and invalidating our TypoExprState, so always fetch it instead of storing. + SemaRef.getTypoExprState(TE).Consumer->saveCurrentPosition(); + + TypoCorrection TC = SemaRef.getTypoExprState(TE).Consumer->peekNextCorrection(); + TypoCorrection Next; + do { + // Fetch the next correction by erasing the typo from the cache and calling + // `TryTransform` which will iterate through corrections in + // `TransformTypoExpr`. + TransformCache.erase(TE); + ExprResult AmbigRes = CheckForRecursiveTypos(TryTransform(E), IsAmbiguous); + + if (!AmbigRes.isInvalid() || IsAmbiguous) { + SemaRef.getTypoExprState(TE).Consumer->resetCorrectionStream(); + SavedTransformCache.erase(TE); + Res = ExprError(); + IsAmbiguous = true; + break; + } + } while ((Next = SemaRef.getTypoExprState(TE).Consumer->peekNextCorrection()) && + Next.getEditDistance(false) == TC.getEditDistance(false)); + + if (IsAmbiguous) + break; + + AmbiguousTypoExprs.remove(TE); + SemaRef.getTypoExprState(TE).Consumer->restoreSavedPosition(); + } + TransformCache = std::move(SavedTransformCache); + } + + // Wipe away any newly created TypoExprs that we don't know about. Since we + // clear any invalid TypoExprs in `CheckForRecursiveTypos`, this is only + // possible if a `TypoExpr` is created during a transformation but then + // fails before we can discover it. + auto &SemaTypoExprs = SemaRef.TypoExprs; + for (auto Iterator = SemaTypoExprs.begin(); Iterator != SemaTypoExprs.end();) { + auto TE = *Iterator; + auto FI = find(TypoExprs, TE); + if (FI != TypoExprs.end()) { + Iterator++; + continue; + } + SemaRef.clearDelayedTypo(TE); + Iterator = SemaTypoExprs.erase(Iterator); + } + SemaRef.TypoExprs = std::move(SavedTypoExprs); + + return Res; + } + public: TransformTypos(Sema &SemaRef, VarDecl *InitDecl, llvm::function_ref<ExprResult(Expr *)> Filter) : BaseTransform(SemaRef), InitDecl(InitDecl), ExprFilter(Filter) {} @@ -7681,49 +7866,13 @@ public: ExprResult TransformBlockExpr(BlockExpr *E) { return Owned(E); } ExprResult Transform(Expr *E) { - ExprResult Res; - while (true) { - Res = TryTransform(E); - - // Exit if either the transform was valid or if there were no TypoExprs - // to transform that still have any untried correction candidates.. - if (!Res.isInvalid() || - !CheckAndAdvanceTypoExprCorrectionStreams()) - break; - } - - // Ensure none of the TypoExprs have multiple typo correction candidates - // with the same edit length that pass all the checks and filters. - // TODO: Properly handle various permutations of possible corrections when - // there is more than one potentially ambiguous typo correction. - // Also, disable typo correction while attempting the transform when - // handling potentially ambiguous typo corrections as any new TypoExprs will - // have been introduced by the application of one of the correction - // candidates and add little to no value if corrected. - SemaRef.DisableTypoCorrection = true; - while (!AmbiguousTypoExprs.empty()) { - auto TE = AmbiguousTypoExprs.back(); - auto Cached = TransformCache[TE]; - auto &State = SemaRef.getTypoExprState(TE); - State.Consumer->saveCurrentPosition(); - TransformCache.erase(TE); - if (!TryTransform(E).isInvalid()) { - State.Consumer->resetCorrectionStream(); - TransformCache.erase(TE); - Res = ExprError(); - break; - } - AmbiguousTypoExprs.remove(TE); - State.Consumer->restoreSavedPosition(); - TransformCache[TE] = Cached; - } - SemaRef.DisableTypoCorrection = false; + bool IsAmbiguous = false; + ExprResult Res = RecursiveTransformLoop(E, IsAmbiguous); - // Ensure that all of the TypoExprs within the current Expr have been found. if (!Res.isUsable()) FindTypoExprs(TypoExprs).TraverseStmt(E); - EmitAllDiagnostics(); + EmitAllDiagnostics(IsAmbiguous); return Res; } diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index c856e37e99e7..87114a0fac63 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -629,7 +629,7 @@ public: } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<RecordMemberExprValidatorCCC>(*this); + return std::make_unique<RecordMemberExprValidatorCCC>(*this); } private: @@ -934,19 +934,19 @@ static bool IsInFnTryBlockHandler(const Scope *S) { return false; } -static VarDecl * -getVarTemplateSpecialization(Sema &S, VarTemplateDecl *VarTempl, +VarDecl * +Sema::getVarTemplateSpecialization(VarTemplateDecl *VarTempl, const TemplateArgumentListInfo *TemplateArgs, const DeclarationNameInfo &MemberNameInfo, SourceLocation TemplateKWLoc) { if (!TemplateArgs) { - S.diagnoseMissingTemplateArguments(TemplateName(VarTempl), - MemberNameInfo.getBeginLoc()); + diagnoseMissingTemplateArguments(TemplateName(VarTempl), + MemberNameInfo.getBeginLoc()); return nullptr; } - DeclResult VDecl = S.CheckVarTemplateId( - VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(), *TemplateArgs); + DeclResult VDecl = CheckVarTemplateId(VarTempl, TemplateKWLoc, + MemberNameInfo.getLoc(), *TemplateArgs); if (VDecl.isInvalid()) return nullptr; VarDecl *Var = cast<VarDecl>(VDecl.get()); @@ -1006,7 +1006,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, // Rederive where we looked up. DeclContext *DC = (SS.isSet() ? computeDeclContext(SS, false) - : BaseType->getAs<RecordType>()->getDecl()); + : BaseType->castAs<RecordType>()->getDecl()); if (ExtraArgs) { ExprResult RetryExpr; @@ -1095,7 +1095,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, "How did we get template arguments here sans a variable template"); if (isa<VarTemplateDecl>(MemberDecl)) { MemberDecl = getVarTemplateSpecialization( - *this, cast<VarTemplateDecl>(MemberDecl), TemplateArgs, + cast<VarTemplateDecl>(MemberDecl), TemplateArgs, R.getLookupNameInfo(), TemplateKWLoc); if (!MemberDecl) return ExprError(); @@ -1160,7 +1160,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, } if (VarTemplateDecl *VarTempl = dyn_cast<VarTemplateDecl>(MemberDecl)) { if (VarDecl *Var = getVarTemplateSpecialization( - *this, VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc)) + VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc)) return BuildMemberExpr( BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, FoundDecl, /*HadMultipleCandidates=*/false, MemberNameInfo, diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 040cfdd30c7a..e18621e42a6b 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -67,7 +67,7 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, const ConstantArrayType *CAT = Context.getAsConstantArrayType(S->getType()); assert(CAT && "String literal not of constant array type!"); QualType StrTy = Context.getConstantArrayType( - CAT->getElementType(), llvm::APInt(32, StrBuf.size() + 1), + CAT->getElementType(), llvm::APInt(32, StrBuf.size() + 1), nullptr, CAT->getSizeModifier(), CAT->getIndexTypeCVRQualifiers()); S = StringLiteral::Create(Context, StrBuf, StringLiteral::Ascii, /*Pascal=*/false, StrTy, &StrLocs[0], @@ -2115,7 +2115,7 @@ class ObjCInterfaceOrSuperCCC final : public CorrectionCandidateCallback { } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<ObjCInterfaceOrSuperCCC>(*this); + return std::make_unique<ObjCInterfaceOrSuperCCC>(*this); } }; diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index bc1069609336..10cb7acad567 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -16,6 +16,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" #include "clang/AST/TypeLoc.h" +#include "clang/Basic/CharInfo.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/Designator.h" #include "clang/Sema/Initialization.h" @@ -197,7 +198,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT, llvm::APInt ConstVal(32, StrLength); // Return a new array type (C99 6.7.8p22). DeclT = S.Context.getConstantArrayType(IAT->getElementType(), - ConstVal, + ConstVal, nullptr, ArrayType::Normal, 0); updateStringLiteralType(Str, DeclT); return; @@ -271,13 +272,24 @@ namespace { /// point. CheckDesignatedInitializer() recursively steps into the /// designated subobject and manages backing out the recursion to /// initialize the subobjects after the one designated. +/// +/// If an initializer list contains any designators, we build a placeholder +/// structured list even in 'verify only' mode, so that we can track which +/// elements need 'empty' initializtion. class InitListChecker { Sema &SemaRef; - bool hadError; - bool VerifyOnly; // no diagnostics, no structure building + bool hadError = false; + bool VerifyOnly; // No diagnostics. bool TreatUnavailableAsInvalid; // Used only in VerifyOnly mode. - llvm::DenseMap<InitListExpr *, InitListExpr *> SyntacticToSemantic; - InitListExpr *FullyStructuredList; + bool InOverloadResolution; + InitListExpr *FullyStructuredList = nullptr; + NoInitExpr *DummyExpr = nullptr; + + NoInitExpr *getDummyInit() { + if (!DummyExpr) + DummyExpr = new (SemaRef.Context) NoInitExpr(SemaRef.Context.VoidTy); + return DummyExpr; + } void CheckImplicitInitList(const InitializedEntity &Entity, InitListExpr *ParentIList, QualType T, @@ -352,14 +364,71 @@ class InitListChecker { void UpdateStructuredListElement(InitListExpr *StructuredList, unsigned &StructuredIndex, Expr *expr); + InitListExpr *createInitListExpr(QualType CurrentObjectType, + SourceRange InitRange, + unsigned ExpectedNumInits); int numArrayElements(QualType DeclType); int numStructUnionElements(QualType DeclType); - static ExprResult PerformEmptyInit(Sema &SemaRef, - SourceLocation Loc, - const InitializedEntity &Entity, - bool VerifyOnly, - bool TreatUnavailableAsInvalid); + ExprResult PerformEmptyInit(SourceLocation Loc, + const InitializedEntity &Entity); + + /// Diagnose that OldInit (or part thereof) has been overridden by NewInit. + void diagnoseInitOverride(Expr *OldInit, SourceRange NewInitRange, + bool FullyOverwritten = true) { + // Overriding an initializer via a designator is valid with C99 designated + // initializers, but ill-formed with C++20 designated initializers. + unsigned DiagID = SemaRef.getLangOpts().CPlusPlus + ? diag::ext_initializer_overrides + : diag::warn_initializer_overrides; + + if (InOverloadResolution && SemaRef.getLangOpts().CPlusPlus) { + // In overload resolution, we have to strictly enforce the rules, and so + // don't allow any overriding of prior initializers. This matters for a + // case such as: + // + // union U { int a, b; }; + // struct S { int a, b; }; + // void f(U), f(S); + // + // Here, f({.a = 1, .b = 2}) is required to call the struct overload. For + // consistency, we disallow all overriding of prior initializers in + // overload resolution, not only overriding of union members. + hadError = true; + } else if (OldInit->getType().isDestructedType() && !FullyOverwritten) { + // If we'll be keeping around the old initializer but overwriting part of + // the object it initialized, and that object is not trivially + // destructible, this can leak. Don't allow that, not even as an + // extension. + // + // FIXME: It might be reasonable to allow this in cases where the part of + // the initializer that we're overriding has trivial destruction. + DiagID = diag::err_initializer_overrides_destructed; + } else if (!OldInit->getSourceRange().isValid()) { + // We need to check on source range validity because the previous + // initializer does not have to be an explicit initializer. e.g., + // + // struct P { int a, b; }; + // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 }; + // + // There is an overwrite taking place because the first braced initializer + // list "{ .a = 2 }" already provides value for .p.b (which is zero). + // + // Such overwrites are harmless, so we don't diagnose them. (Note that in + // C++, this cannot be reached unless we've already seen and diagnosed a + // different conformance issue, such as a mixture of designated and + // non-designated initializers or a multi-level designator.) + return; + } + + if (!VerifyOnly) { + SemaRef.Diag(NewInitRange.getBegin(), DiagID) + << NewInitRange << FullyOverwritten << OldInit->getType(); + SemaRef.Diag(OldInit->getBeginLoc(), diag::note_previous_initializer) + << (OldInit->HasSideEffects(SemaRef.Context) && FullyOverwritten) + << OldInit->getSourceRange(); + } + } // Explanation on the "FillWithNoInit" mode: // @@ -399,9 +468,9 @@ class InitListChecker { SourceLocation Loc); public: - InitListChecker(Sema &S, const InitializedEntity &Entity, - InitListExpr *IL, QualType &T, bool VerifyOnly, - bool TreatUnavailableAsInvalid); + InitListChecker(Sema &S, const InitializedEntity &Entity, InitListExpr *IL, + QualType &T, bool VerifyOnly, bool TreatUnavailableAsInvalid, + bool InOverloadResolution = false); bool HadError() { return hadError; } // Retrieves the fully-structured initializer list used for @@ -411,11 +480,8 @@ public: } // end anonymous namespace -ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef, - SourceLocation Loc, - const InitializedEntity &Entity, - bool VerifyOnly, - bool TreatUnavailableAsInvalid) { +ExprResult InitListChecker::PerformEmptyInit(SourceLocation Loc, + const InitializedEntity &Entity) { InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc, true); MultiExprArg SubInit; @@ -517,43 +583,44 @@ ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef, << Entity.getElementIndex(); } } + hadError = true; return ExprError(); } - return VerifyOnly ? ExprResult(static_cast<Expr *>(nullptr)) + return VerifyOnly ? ExprResult() : InitSeq.Perform(SemaRef, Entity, Kind, SubInit); } void InitListChecker::CheckEmptyInitializable(const InitializedEntity &Entity, SourceLocation Loc) { - assert(VerifyOnly && - "CheckEmptyInitializable is only inteded for verification mode."); - if (PerformEmptyInit(SemaRef, Loc, Entity, /*VerifyOnly*/true, - TreatUnavailableAsInvalid).isInvalid()) - hadError = true; + // If we're building a fully-structured list, we'll check this at the end + // once we know which elements are actually initialized. Otherwise, we know + // that there are no designators so we can just check now. + if (FullyStructuredList) + return; + PerformEmptyInit(Loc, Entity); } void InitListChecker::FillInEmptyInitForBase( unsigned Init, const CXXBaseSpecifier &Base, const InitializedEntity &ParentEntity, InitListExpr *ILE, bool &RequiresSecondPass, bool FillWithNoInit) { - assert(Init < ILE->getNumInits() && "should have been expanded"); - InitializedEntity BaseEntity = InitializedEntity::InitializeBase( SemaRef.Context, &Base, false, &ParentEntity); - if (!ILE->getInit(Init)) { - ExprResult BaseInit = - FillWithNoInit - ? new (SemaRef.Context) NoInitExpr(Base.getType()) - : PerformEmptyInit(SemaRef, ILE->getEndLoc(), BaseEntity, - /*VerifyOnly*/ false, TreatUnavailableAsInvalid); + if (Init >= ILE->getNumInits() || !ILE->getInit(Init)) { + ExprResult BaseInit = FillWithNoInit + ? new (SemaRef.Context) NoInitExpr(Base.getType()) + : PerformEmptyInit(ILE->getEndLoc(), BaseEntity); if (BaseInit.isInvalid()) { hadError = true; return; } - ILE->setInit(Init, BaseInit.getAs<Expr>()); + if (!VerifyOnly) { + assert(Init < ILE->getNumInits() && "should have been expanded"); + ILE->setInit(Init, BaseInit.getAs<Expr>()); + } } else if (InitListExpr *InnerILE = dyn_cast<InitListExpr>(ILE->getInit(Init))) { FillInEmptyInitializations(BaseEntity, InnerILE, RequiresSecondPass, @@ -576,12 +643,14 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, InitializedEntity MemberEntity = InitializedEntity::InitializeMember(Field, &ParentEntity); - if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) - if (!RType->getDecl()->isUnion()) - assert(Init < NumInits && "This ILE should have been expanded"); - if (Init >= NumInits || !ILE->getInit(Init)) { + if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) + if (!RType->getDecl()->isUnion()) + assert((Init < NumInits || VerifyOnly) && + "This ILE should have been expanded"); + if (FillWithNoInit) { + assert(!VerifyOnly && "should not fill with no-init in verify-only mode"); Expr *Filler = new (SemaRef.Context) NoInitExpr(Field->getType()); if (Init < NumInits) ILE->setInit(Init, Filler); @@ -594,6 +663,9 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, // members in the aggregate, then each member not explicitly initialized // shall be initialized from its brace-or-equal-initializer [...] if (Field->hasInClassInitializer()) { + if (VerifyOnly) + return; + ExprResult DIE = SemaRef.BuildCXXDefaultInitExpr(Loc, Field); if (DIE.isInvalid()) { hadError = true; @@ -610,28 +682,28 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, } if (Field->getType()->isReferenceType()) { - // C++ [dcl.init.aggr]p9: - // If an incomplete or empty initializer-list leaves a - // member of reference type uninitialized, the program is - // ill-formed. - SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized) - << Field->getType() - << ILE->getSyntacticForm()->getSourceRange(); - SemaRef.Diag(Field->getLocation(), - diag::note_uninit_reference_member); + if (!VerifyOnly) { + // C++ [dcl.init.aggr]p9: + // If an incomplete or empty initializer-list leaves a + // member of reference type uninitialized, the program is + // ill-formed. + SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized) + << Field->getType() + << ILE->getSyntacticForm()->getSourceRange(); + SemaRef.Diag(Field->getLocation(), + diag::note_uninit_reference_member); + } hadError = true; return; } - ExprResult MemberInit = PerformEmptyInit(SemaRef, Loc, MemberEntity, - /*VerifyOnly*/false, - TreatUnavailableAsInvalid); + ExprResult MemberInit = PerformEmptyInit(Loc, MemberEntity); if (MemberInit.isInvalid()) { hadError = true; return; } - if (hadError) { + if (hadError || VerifyOnly) { // Do nothing } else if (Init < NumInits) { ILE->setInit(Init, MemberInit.getAs<Expr>()); @@ -644,14 +716,15 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, RequiresSecondPass = true; } } else if (InitListExpr *InnerILE - = dyn_cast<InitListExpr>(ILE->getInit(Init))) + = dyn_cast<InitListExpr>(ILE->getInit(Init))) { FillInEmptyInitializations(MemberEntity, InnerILE, RequiresSecondPass, ILE, Init, FillWithNoInit); - else if (DesignatedInitUpdateExpr *InnerDIUE - = dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init))) + } else if (DesignatedInitUpdateExpr *InnerDIUE = + dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init))) { FillInEmptyInitializations(MemberEntity, InnerDIUE->getUpdater(), RequiresSecondPass, ILE, Init, /*FillWithNoInit =*/true); + } } /// Recursively replaces NULL values within the given initializer list @@ -667,6 +740,11 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, assert((ILE->getType() != SemaRef.Context.VoidTy) && "Should not have void type"); + // We don't need to do any checks when just filling NoInitExprs; that can't + // fail. + if (FillWithNoInit && VerifyOnly) + return; + // If this is a nested initializer list, we might have changed its contents // (and therefore some of its properties, such as instantiation-dependence) // while filling it in. Inform the outer initializer list so that its state @@ -709,7 +787,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, unsigned NumElems = numStructUnionElements(ILE->getType()); if (RDecl->hasFlexibleArrayMember()) ++NumElems; - if (ILE->getNumInits() < NumElems) + if (!VerifyOnly && ILE->getNumInits() < NumElems) ILE->resizeInits(SemaRef.Context, NumElems); unsigned Init = 0; @@ -771,6 +849,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, } else ElementType = ILE->getType(); + bool SkipEmptyInitChecks = false; for (unsigned Init = 0; Init != NumElements; ++Init) { if (hadError) return; @@ -779,21 +858,25 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, ElementEntity.getKind() == InitializedEntity::EK_VectorElement) ElementEntity.setElementIndex(Init); - if (Init >= NumInits && ILE->hasArrayFiller()) + if (Init >= NumInits && (ILE->hasArrayFiller() || SkipEmptyInitChecks)) return; Expr *InitExpr = (Init < NumInits ? ILE->getInit(Init) : nullptr); if (!InitExpr && Init < NumInits && ILE->hasArrayFiller()) ILE->setInit(Init, ILE->getArrayFiller()); else if (!InitExpr && !ILE->hasArrayFiller()) { + // In VerifyOnly mode, there's no point performing empty initialization + // more than once. + if (SkipEmptyInitChecks) + continue; + Expr *Filler = nullptr; if (FillWithNoInit) Filler = new (SemaRef.Context) NoInitExpr(ElementType); else { ExprResult ElementInit = - PerformEmptyInit(SemaRef, ILE->getEndLoc(), ElementEntity, - /*VerifyOnly*/ false, TreatUnavailableAsInvalid); + PerformEmptyInit(ILE->getEndLoc(), ElementEntity); if (ElementInit.isInvalid()) { hadError = true; return; @@ -804,6 +887,8 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, if (hadError) { // Do nothing + } else if (VerifyOnly) { + SkipEmptyInitChecks = true; } else if (Init < NumInits) { // For arrays, just set the expression used for value-initialization // of the "holes" in the array. @@ -829,34 +914,46 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, } } } else if (InitListExpr *InnerILE - = dyn_cast_or_null<InitListExpr>(InitExpr)) + = dyn_cast_or_null<InitListExpr>(InitExpr)) { FillInEmptyInitializations(ElementEntity, InnerILE, RequiresSecondPass, ILE, Init, FillWithNoInit); - else if (DesignatedInitUpdateExpr *InnerDIUE - = dyn_cast_or_null<DesignatedInitUpdateExpr>(InitExpr)) + } else if (DesignatedInitUpdateExpr *InnerDIUE = + dyn_cast_or_null<DesignatedInitUpdateExpr>(InitExpr)) { FillInEmptyInitializations(ElementEntity, InnerDIUE->getUpdater(), RequiresSecondPass, ILE, Init, /*FillWithNoInit =*/true); + } } } +static bool hasAnyDesignatedInits(const InitListExpr *IL) { + for (const Stmt *Init : *IL) + if (Init && isa<DesignatedInitExpr>(Init)) + return true; + return false; +} + InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity, - InitListExpr *IL, QualType &T, - bool VerifyOnly, - bool TreatUnavailableAsInvalid) - : SemaRef(S), VerifyOnly(VerifyOnly), - TreatUnavailableAsInvalid(TreatUnavailableAsInvalid) { - // FIXME: Check that IL isn't already the semantic form of some other - // InitListExpr. If it is, we'd create a broken AST. - - hadError = false; - - FullyStructuredList = - getStructuredSubobjectInit(IL, 0, T, nullptr, 0, IL->getSourceRange()); + InitListExpr *IL, QualType &T, bool VerifyOnly, + bool TreatUnavailableAsInvalid, + bool InOverloadResolution) + : SemaRef(S), VerifyOnly(VerifyOnly), + TreatUnavailableAsInvalid(TreatUnavailableAsInvalid), + InOverloadResolution(InOverloadResolution) { + if (!VerifyOnly || hasAnyDesignatedInits(IL)) { + FullyStructuredList = + createInitListExpr(T, IL->getSourceRange(), IL->getNumInits()); + + // FIXME: Check that IL isn't already the semantic form of some other + // InitListExpr. If it is, we'd create a broken AST. + if (!VerifyOnly) + FullyStructuredList->setSyntacticForm(IL); + } + CheckExplicitInitList(Entity, IL, T, FullyStructuredList, /*TopLevelObject=*/true); - if (!hadError && !VerifyOnly) { + if (!hadError && FullyStructuredList) { bool RequiresSecondPass = false; FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass, /*OuterILE=*/nullptr, /*OuterIndex=*/0); @@ -877,7 +974,7 @@ int InitListChecker::numArrayElements(QualType DeclType) { } int InitListChecker::numStructUnionElements(QualType DeclType) { - RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl(); + RecordDecl *structDecl = DeclType->castAs<RecordType>()->getDecl(); int InitializableMembers = 0; if (auto *CXXRD = dyn_cast<CXXRecordDecl>(structDecl)) InitializableMembers += CXXRD->getNumBases(); @@ -936,7 +1033,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, else if (T->isRecordType()) maxElements = numStructUnionElements(T); else if (T->isVectorType()) - maxElements = T->getAs<VectorType>()->getNumElements(); + maxElements = T->castAs<VectorType>()->getNumElements(); else llvm_unreachable("CheckImplicitInitList(): Illegal type"); @@ -963,7 +1060,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, StructuredSubobjectInitList, StructuredSubobjectInitIndex); - if (!VerifyOnly) { + if (StructuredSubobjectInitList) { StructuredSubobjectInitList->setType(T); unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1); @@ -977,7 +1074,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, } // Complain about missing braces. - if ((T->isArrayType() || T->isRecordType()) && + if (!VerifyOnly && (T->isArrayType() || T->isRecordType()) && !ParentIList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) && !isIdiomaticBraceElisionEntity(Entity)) { SemaRef.Diag(StructuredSubobjectInitList->getBeginLoc(), @@ -993,7 +1090,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, // Warn if this type won't be an aggregate in future versions of C++. auto *CXXRD = T->getAsCXXRecordDecl(); - if (CXXRD && CXXRD->hasUserDeclaredConstructor()) { + if (!VerifyOnly && CXXRD && CXXRD->hasUserDeclaredConstructor()) { SemaRef.Diag(StructuredSubobjectInitList->getBeginLoc(), diag::warn_cxx2a_compat_aggregate_init_with_ctors) << StructuredSubobjectInitList->getSourceRange() << T; @@ -1074,67 +1171,46 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity, InitListExpr *IList, QualType &T, InitListExpr *StructuredList, bool TopLevelObject) { - if (!VerifyOnly) { - SyntacticToSemantic[IList] = StructuredList; - StructuredList->setSyntacticForm(IList); - } - unsigned Index = 0, StructuredIndex = 0; CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true, Index, StructuredList, StructuredIndex, TopLevelObject); - if (!VerifyOnly) { + if (StructuredList) { QualType ExprTy = T; if (!ExprTy->isArrayType()) ExprTy = ExprTy.getNonLValueExprType(SemaRef.Context); - IList->setType(ExprTy); + if (!VerifyOnly) + IList->setType(ExprTy); StructuredList->setType(ExprTy); } if (hadError) return; - if (Index < IList->getNumInits()) { + // Don't complain for incomplete types, since we'll get an error elsewhere. + if (Index < IList->getNumInits() && !T->isIncompleteType()) { // We have leftover initializers + bool ExtraInitsIsError = SemaRef.getLangOpts().CPlusPlus || + (SemaRef.getLangOpts().OpenCL && T->isVectorType()); + hadError = ExtraInitsIsError; if (VerifyOnly) { - if (SemaRef.getLangOpts().CPlusPlus || - (SemaRef.getLangOpts().OpenCL && - IList->getType()->isVectorType())) { - hadError = true; - } return; - } - - if (StructuredIndex == 1 && - IsStringInit(StructuredList->getInit(0), T, SemaRef.Context) == - SIF_None) { - unsigned DK = diag::ext_excess_initializers_in_char_array_initializer; - if (SemaRef.getLangOpts().CPlusPlus) { - DK = diag::err_excess_initializers_in_char_array_initializer; - hadError = true; - } - // Special-case + } else if (StructuredIndex == 1 && + IsStringInit(StructuredList->getInit(0), T, SemaRef.Context) == + SIF_None) { + unsigned DK = + ExtraInitsIsError + ? diag::err_excess_initializers_in_char_array_initializer + : diag::ext_excess_initializers_in_char_array_initializer; SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK) << IList->getInit(Index)->getSourceRange(); - } else if (!T->isIncompleteType()) { - // Don't complain for incomplete types, since we'll get an error - // elsewhere - QualType CurrentObjectType = StructuredList->getType(); - int initKind = - CurrentObjectType->isArrayType()? 0 : - CurrentObjectType->isVectorType()? 1 : - CurrentObjectType->isScalarType()? 2 : - CurrentObjectType->isUnionType()? 3 : - 4; - - unsigned DK = diag::ext_excess_initializers; - if (SemaRef.getLangOpts().CPlusPlus) { - DK = diag::err_excess_initializers; - hadError = true; - } - if (SemaRef.getLangOpts().OpenCL && initKind == 1) { - DK = diag::err_excess_initializers; - hadError = true; - } - + } else { + int initKind = T->isArrayType() ? 0 : + T->isVectorType() ? 1 : + T->isScalarType() ? 2 : + T->isUnionType() ? 3 : + 4; + + unsigned DK = ExtraInitsIsError ? diag::err_excess_initializers + : diag::ext_excess_initializers; SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK) << initKind << IList->getInit(Index)->getSourceRange(); } @@ -1188,7 +1264,7 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, } else if (DeclType->isRecordType()) { assert(DeclType->isAggregateType() && "non-aggregate records should be handed in CheckSubElementType"); - RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); + RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl(); auto Bases = CXXRecordDecl::base_class_range(CXXRecordDecl::base_class_iterator(), CXXRecordDecl::base_class_iterator()); @@ -1246,42 +1322,22 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, if (SubInitList->getNumInits() == 1 && IsStringInit(SubInitList->getInit(0), ElemType, SemaRef.Context) == SIF_None) { + // FIXME: It would be more faithful and no less correct to include an + // InitListExpr in the semantic form of the initializer list in this case. expr = SubInitList->getInit(0); - } else if (!SemaRef.getLangOpts().CPlusPlus) { - InitListExpr *InnerStructuredList - = getStructuredSubobjectInit(IList, Index, ElemType, - StructuredList, StructuredIndex, - SubInitList->getSourceRange(), true); - CheckExplicitInitList(Entity, SubInitList, ElemType, - InnerStructuredList); - - if (!hadError && !VerifyOnly) { - bool RequiresSecondPass = false; - FillInEmptyInitializations(Entity, InnerStructuredList, - RequiresSecondPass, StructuredList, - StructuredIndex); - if (RequiresSecondPass && !hadError) - FillInEmptyInitializations(Entity, InnerStructuredList, - RequiresSecondPass, StructuredList, - StructuredIndex); - } - ++StructuredIndex; - ++Index; - return; } - // C++ initialization is handled later. + // Nested aggregate initialization and C++ initialization are handled later. } else if (isa<ImplicitValueInitExpr>(expr)) { // This happens during template instantiation when we see an InitListExpr // that we've already checked once. assert(SemaRef.Context.hasSameType(expr->getType(), ElemType) && "found implicit initialization for the wrong type"); - if (!VerifyOnly) - UpdateStructuredListElement(StructuredList, StructuredIndex, expr); + UpdateStructuredListElement(StructuredList, StructuredIndex, expr); ++Index; return; } - if (SemaRef.getLangOpts().CPlusPlus) { + if (SemaRef.getLangOpts().CPlusPlus || isa<InitListExpr>(expr)) { // C++ [dcl.init.aggr]p2: // Each member is copy-initialized from the corresponding // initializer-clause. @@ -1289,7 +1345,16 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // FIXME: Better EqualLoc? InitializationKind Kind = InitializationKind::CreateCopy(expr->getBeginLoc(), SourceLocation()); - InitializationSequence Seq(SemaRef, Entity, Kind, expr, + + // Vector elements can be initialized from other vectors in which case + // we need initialization entity with a type of a vector (and not a vector + // element!) initializing multiple vector elements. + auto TmpEntity = + (ElemType->isExtVectorType() && !Entity.getType()->isExtVectorType()) + ? InitializedEntity::InitializeTemporary(ElemType) + : Entity; + + InitializationSequence Seq(SemaRef, TmpEntity, Kind, expr, /*TopLevelOfInitList*/ true); // C++14 [dcl.init.aggr]p13: @@ -1300,15 +1365,18 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // assignment-expression. if (Seq || isa<InitListExpr>(expr)) { if (!VerifyOnly) { - ExprResult Result = - Seq.Perform(SemaRef, Entity, Kind, expr); + ExprResult Result = Seq.Perform(SemaRef, TmpEntity, Kind, expr); if (Result.isInvalid()) hadError = true; UpdateStructuredListElement(StructuredList, StructuredIndex, Result.getAs<Expr>()); - } else if (!Seq) + } else if (!Seq) { hadError = true; + } else if (StructuredList) { + UpdateStructuredListElement(StructuredList, StructuredIndex, + getDummyInit()); + } ++Index; return; } @@ -1325,10 +1393,11 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // type here, though. if (IsStringInit(expr, arrayType, SemaRef.Context) == SIF_None) { - if (!VerifyOnly) { + // FIXME: Should we do this checking in verify-only mode? + if (!VerifyOnly) CheckStringInit(expr, ElemType, arrayType, SemaRef); + if (StructuredList) UpdateStructuredListElement(StructuredList, StructuredIndex, expr); - } ++Index; return; } @@ -1354,8 +1423,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, hadError = true; else { ExprRes = SemaRef.DefaultFunctionArrayLvalueConversion(ExprRes.get()); - if (ExprRes.isInvalid()) - hadError = true; + if (ExprRes.isInvalid()) + hadError = true; } UpdateStructuredListElement(StructuredList, StructuredIndex, ExprRes.getAs<Expr>()); @@ -1380,10 +1449,15 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, ++StructuredIndex; } else { if (!VerifyOnly) { - // We cannot initialize this element, so let - // PerformCopyInitialization produce the appropriate diagnostic. - SemaRef.PerformCopyInitialization(Entity, SourceLocation(), expr, - /*TopLevelOfInitList=*/true); + // We cannot initialize this element, so let PerformCopyInitialization + // produce the appropriate diagnostic. We already checked that this + // initialization will fail. + ExprResult Copy = + SemaRef.PerformCopyInitialization(Entity, SourceLocation(), expr, + /*TopLevelOfInitList=*/true); + (void)Copy; + assert(Copy.isInvalid() && + "expected non-aggregate initialization to fail"); } hadError = true; ++Index; @@ -1416,7 +1490,7 @@ void InitListChecker::CheckComplexType(const InitializedEntity &Entity, << IList->getSourceRange(); // Initialize the complex number. - QualType elementType = DeclType->getAs<ComplexType>()->getElementType(); + QualType elementType = DeclType->castAs<ComplexType>()->getElementType(); InitializedEntity ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); @@ -1467,17 +1541,18 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity, return; } + ExprResult Result; if (VerifyOnly) { - if (!SemaRef.CanPerformCopyInitialization(Entity,expr)) - hadError = true; - ++Index; - return; + if (SemaRef.CanPerformCopyInitialization(Entity, expr)) + Result = getDummyInit(); + else + Result = ExprError(); + } else { + Result = + SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr, + /*TopLevelOfInitList=*/true); } - ExprResult Result = - SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr, - /*TopLevelOfInitList=*/true); - Expr *ResultExpr = nullptr; if (Result.isInvalid()) @@ -1485,8 +1560,9 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity, else { ResultExpr = Result.getAs<Expr>(); - if (ResultExpr != expr) { + if (ResultExpr != expr && !VerifyOnly) { // The type was promoted, update initializer list. + // FIXME: Why are we updating the syntactic init list? IList->setInit(Index, ResultExpr); } } @@ -1528,22 +1604,25 @@ void InitListChecker::CheckReferenceType(const InitializedEntity &Entity, return; } + ExprResult Result; if (VerifyOnly) { - if (!SemaRef.CanPerformCopyInitialization(Entity,expr)) - hadError = true; - ++Index; - return; + if (SemaRef.CanPerformCopyInitialization(Entity,expr)) + Result = getDummyInit(); + else + Result = ExprError(); + } else { + Result = + SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr, + /*TopLevelOfInitList=*/true); } - ExprResult Result = - SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr, - /*TopLevelOfInitList=*/true); - if (Result.isInvalid()) hadError = true; expr = Result.getAs<Expr>(); - IList->setInit(Index, expr); + // FIXME: Why are we updating the syntactic init list? + if (!VerifyOnly) + IList->setInit(Index, expr); if (hadError) ++StructuredIndex; @@ -1557,17 +1636,16 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex) { - const VectorType *VT = DeclType->getAs<VectorType>(); + const VectorType *VT = DeclType->castAs<VectorType>(); unsigned maxElements = VT->getNumElements(); unsigned numEltsInit = 0; QualType elementType = VT->getElementType(); if (Index >= IList->getNumInits()) { // Make sure the element type can be value-initialized. - if (VerifyOnly) - CheckEmptyInitializable( - InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity), - IList->getEndLoc()); + CheckEmptyInitializable( + InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity), + IList->getEndLoc()); return; } @@ -1576,25 +1654,27 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity, // instead of breaking it apart (which is doomed to failure anyway). Expr *Init = IList->getInit(Index); if (!isa<InitListExpr>(Init) && Init->getType()->isVectorType()) { + ExprResult Result; if (VerifyOnly) { - if (!SemaRef.CanPerformCopyInitialization(Entity, Init)) - hadError = true; - ++Index; - return; + if (SemaRef.CanPerformCopyInitialization(Entity, Init)) + Result = getDummyInit(); + else + Result = ExprError(); + } else { + Result = + SemaRef.PerformCopyInitialization(Entity, Init->getBeginLoc(), Init, + /*TopLevelOfInitList=*/true); } - ExprResult Result = - SemaRef.PerformCopyInitialization(Entity, Init->getBeginLoc(), Init, - /*TopLevelOfInitList=*/true); - Expr *ResultExpr = nullptr; if (Result.isInvalid()) hadError = true; // types weren't compatible. else { ResultExpr = Result.getAs<Expr>(); - if (ResultExpr != Init) { + if (ResultExpr != Init && !VerifyOnly) { // The type was promoted, update initializer list. + // FIXME: Why are we updating the syntactic init list? IList->setInit(Index, ResultExpr); } } @@ -1613,8 +1693,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity, for (unsigned i = 0; i < maxElements; ++i, ++numEltsInit) { // Don't attempt to go past the end of the init list if (Index >= IList->getNumInits()) { - if (VerifyOnly) - CheckEmptyInitializable(ElementEntity, IList->getEndLoc()); + CheckEmptyInitializable(ElementEntity, IList->getEndLoc()); break; } @@ -1627,7 +1706,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity, return; bool isBigEndian = SemaRef.Context.getTargetInfo().isBigEndian(); - const VectorType *T = Entity.getType()->getAs<VectorType>(); + const VectorType *T = Entity.getType()->castAs<VectorType>(); if (isBigEndian && (T->getVectorKind() == VectorType::NeonVector || T->getVectorKind() == VectorType::NeonPolyVector)) { // The ability to use vector initializer lists is a GNU vector extension @@ -1683,7 +1762,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity, ++numEltsInit; } else { QualType VecType; - const VectorType *IVT = IType->getAs<VectorType>(); + const VectorType *IVT = IType->castAs<VectorType>(); unsigned numIElts = IVT->getNumElements(); if (IType->isExtVectorType()) @@ -1757,8 +1836,10 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, // of the structured initializer list doesn't match exactly, // because doing so would involve allocating one character // constant for each string. - if (!VerifyOnly) { + // FIXME: Should we do these checks in verify-only mode too? + if (!VerifyOnly) CheckStringInit(IList->getInit(Index), DeclType, arrayType, SemaRef); + if (StructuredList) { UpdateStructuredListElement(StructuredList, StructuredIndex, IList->getInit(Index)); StructuredList->resizeInits(SemaRef.Context, StructuredIndex); @@ -1854,15 +1935,14 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, SemaRef.Diag(IList->getBeginLoc(), diag::ext_typecheck_zero_array_size); } - DeclType = SemaRef.Context.getConstantArrayType(elementType, maxElements, - ArrayType::Normal, 0); + DeclType = SemaRef.Context.getConstantArrayType( + elementType, maxElements, nullptr, ArrayType::Normal, 0); } - if (!hadError && VerifyOnly) { + if (!hadError) { // If there are any members of the array that get value-initialized, check // that is possible. That happens if we know the bound and don't have // enough elements, or if we're performing an array new with an unknown // bound. - // FIXME: This needs to detect holes left by designated initializers too. if ((maxElementsKnown && elementIndex < maxElements) || Entity.isVariableLengthArrayNew()) CheckEmptyInitializable( @@ -1915,7 +1995,7 @@ void InitListChecker::CheckStructUnionTypes( bool SubobjectIsDesignatorContext, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex, bool TopLevelObject) { - RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl(); + RecordDecl *structDecl = DeclType->castAs<RecordType>()->getDecl(); // If the record is invalid, some of it's members are invalid. To avoid // confusion, we forgo checking the intializer for the entire record. @@ -1927,7 +2007,7 @@ void InitListChecker::CheckStructUnionTypes( } if (DeclType->isUnionType() && IList->getNumInits() == 0) { - RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); + RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl(); if (!VerifyOnly) for (FieldDecl *FD : RD->fields()) { @@ -1939,8 +2019,9 @@ void InitListChecker::CheckStructUnionTypes( } // If there's a default initializer, use it. - if (isa<CXXRecordDecl>(RD) && cast<CXXRecordDecl>(RD)->hasInClassInitializer()) { - if (VerifyOnly) + if (isa<CXXRecordDecl>(RD) && + cast<CXXRecordDecl>(RD)->hasInClassInitializer()) { + if (!StructuredList) return; for (RecordDecl::field_iterator FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) { @@ -1957,11 +2038,10 @@ void InitListChecker::CheckStructUnionTypes( for (RecordDecl::field_iterator FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) { if (!Field->isUnnamedBitfield()) { - if (VerifyOnly) - CheckEmptyInitializable( - InitializedEntity::InitializeMember(*Field, &Entity), - IList->getEndLoc()); - else + CheckEmptyInitializable( + InitializedEntity::InitializeMember(*Field, &Entity), + IList->getEndLoc()); + if (StructuredList) StructuredList->setInitializedFieldInUnion(*Field); break; } @@ -1987,7 +2067,7 @@ void InitListChecker::CheckStructUnionTypes( CheckSubElementType(BaseEntity, IList, Base.getType(), Index, StructuredList, StructuredIndex); InitializedSomething = true; - } else if (VerifyOnly) { + } else { CheckEmptyInitializable(BaseEntity, InitLoc); } @@ -2002,7 +2082,7 @@ void InitListChecker::CheckStructUnionTypes( // anything except look at designated initializers; That's okay, // because an error should get printed out elsewhere. It might be // worthwhile to skip over the rest of the initializer, though. - RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); + RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl(); RecordDecl::field_iterator FieldEnd = RD->field_end(); bool CheckForMissingFields = !IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()); @@ -2095,7 +2175,7 @@ void InitListChecker::CheckStructUnionTypes( StructuredList, StructuredIndex); InitializedSomething = true; - if (DeclType->isUnionType() && !VerifyOnly) { + if (DeclType->isUnionType() && StructuredList) { // Initialize the first field within the union. StructuredList->setInitializedFieldInUnion(*Field); } @@ -2119,10 +2199,10 @@ void InitListChecker::CheckStructUnionTypes( } } - // Check that any remaining fields can be value-initialized. - if (VerifyOnly && Field != FieldEnd && !DeclType->isUnionType() && + // Check that any remaining fields can be value-initialized if we're not + // building a structured list. (If we are, we'll check this later.) + if (!StructuredList && Field != FieldEnd && !DeclType->isUnionType() && !Field->getType()->isIncompleteArrayType()) { - // FIXME: Should check for holes left by designated initializers too. for (; Field != FieldEnd && !hadError; ++Field) { if (!Field->isUnnamedBitfield() && !Field->hasInClassInitializer()) CheckEmptyInitializable( @@ -2227,7 +2307,7 @@ class FieldInitializerValidatorCCC final : public CorrectionCandidateCallback { } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<FieldInitializerValidatorCCC>(*this); + return std::make_unique<FieldInitializerValidatorCCC>(*this); } private: @@ -2257,7 +2337,9 @@ class FieldInitializerValidatorCCC final : public CorrectionCandidateCallback { /// /// @param NextField If non-NULL and the first designator in @p DIE is /// a field, this will be set to the field declaration corresponding -/// to the field named by the designator. +/// to the field named by the designator. On input, this is expected to be +/// the next field that would be initialized in the absence of designation, +/// if the complete object being initialized is a struct. /// /// @param NextElementIndex If non-NULL and the first designator in @p /// DIE is an array designator or GNU array-range designator, this @@ -2285,6 +2367,29 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, bool FinishSubobjectInit, bool TopLevelObject) { if (DesigIdx == DIE->size()) { + // C++20 designated initialization can result in direct-list-initialization + // of the designated subobject. This is the only way that we can end up + // performing direct initialization as part of aggregate initialization, so + // it needs special handling. + if (DIE->isDirectInit()) { + Expr *Init = DIE->getInit(); + assert(isa<InitListExpr>(Init) && + "designator result in direct non-list initialization?"); + InitializationKind Kind = InitializationKind::CreateDirectList( + DIE->getBeginLoc(), Init->getBeginLoc(), Init->getEndLoc()); + InitializationSequence Seq(SemaRef, Entity, Kind, Init, + /*TopLevelOfInitList*/ true); + if (StructuredList) { + ExprResult Result = VerifyOnly + ? getDummyInit() + : Seq.Perform(SemaRef, Entity, Kind, Init); + UpdateStructuredListElement(StructuredList, StructuredIndex, + Result.get()); + } + ++Index; + return !Seq; + } + // Check the actual initialization for the designated object type. bool prevHadError = hadError; @@ -2308,14 +2413,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, DesignatedInitExpr::Designator *D = DIE->getDesignator(DesigIdx); bool IsFirstDesignator = (DesigIdx == 0); - if (!VerifyOnly) { - assert((IsFirstDesignator || StructuredList) && - "Need a non-designated initializer list to start from"); - + if (IsFirstDesignator ? FullyStructuredList : StructuredList) { // Determine the structural initializer list that corresponds to the // current subobject. if (IsFirstDesignator) - StructuredList = SyntacticToSemantic.lookup(IList); + StructuredList = FullyStructuredList; else { Expr *ExistingInit = StructuredIndex < StructuredList->getNumInits() ? StructuredList->getInit(StructuredIndex) : nullptr; @@ -2329,48 +2431,42 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, else if (InitListExpr *Result = dyn_cast<InitListExpr>(ExistingInit)) StructuredList = Result; else { - if (DesignatedInitUpdateExpr *E = - dyn_cast<DesignatedInitUpdateExpr>(ExistingInit)) - StructuredList = E->getUpdater(); - else { - DesignatedInitUpdateExpr *DIUE = new (SemaRef.Context) - DesignatedInitUpdateExpr(SemaRef.Context, D->getBeginLoc(), - ExistingInit, DIE->getEndLoc()); - StructuredList->updateInit(SemaRef.Context, StructuredIndex, DIUE); - StructuredList = DIUE->getUpdater(); - } - - // We need to check on source range validity because the previous - // initializer does not have to be an explicit initializer. e.g., + // We are creating an initializer list that initializes the + // subobjects of the current object, but there was already an + // initialization that completely initialized the current + // subobject, e.g., by a compound literal: // - // struct P { int a, b; }; - // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 }; + // struct X { int a, b; }; + // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 }; // - // There is an overwrite taking place because the first braced initializer - // list "{ .a = 2 }" already provides value for .p.b (which is zero). - if (ExistingInit->getSourceRange().isValid()) { - // We are creating an initializer list that initializes the - // subobjects of the current object, but there was already an - // initialization that completely initialized the current - // subobject, e.g., by a compound literal: - // - // struct X { int a, b; }; - // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 }; - // - // Here, xs[0].a == 0 and xs[0].b == 3, since the second, - // designated initializer re-initializes the whole - // subobject [0], overwriting previous initializers. - SemaRef.Diag(D->getBeginLoc(), - diag::warn_subobject_initializer_overrides) - << SourceRange(D->getBeginLoc(), DIE->getEndLoc()); - - SemaRef.Diag(ExistingInit->getBeginLoc(), - diag::note_previous_initializer) - << /*FIXME:has side effects=*/0 << ExistingInit->getSourceRange(); + // Here, xs[0].a == 1 and xs[0].b == 3, since the second, + // designated initializer re-initializes only its current object + // subobject [0].b. + diagnoseInitOverride(ExistingInit, + SourceRange(D->getBeginLoc(), DIE->getEndLoc()), + /*FullyOverwritten=*/false); + + if (!VerifyOnly) { + if (DesignatedInitUpdateExpr *E = + dyn_cast<DesignatedInitUpdateExpr>(ExistingInit)) + StructuredList = E->getUpdater(); + else { + DesignatedInitUpdateExpr *DIUE = new (SemaRef.Context) + DesignatedInitUpdateExpr(SemaRef.Context, D->getBeginLoc(), + ExistingInit, DIE->getEndLoc()); + StructuredList->updateInit(SemaRef.Context, StructuredIndex, DIUE); + StructuredList = DIUE->getUpdater(); + } + } else { + // We don't need to track the structured representation of a + // designated init update of an already-fully-initialized object in + // verify-only mode. The only reason we would need the structure is + // to determine where the uninitialized "holes" are, and in this + // case, we know there aren't any and we can't introduce any. + StructuredList = nullptr; } } } - assert(StructuredList && "Expected a structured initializer list"); } if (D->isFieldDesignator()) { @@ -2453,10 +2549,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, } } - unsigned FieldIndex = 0; - + unsigned NumBases = 0; if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RT->getDecl())) - FieldIndex = CXXRD->getNumBases(); + NumBases = CXXRD->getNumBases(); + + unsigned FieldIndex = NumBases; for (auto *FI : RT->getDecl()->fields()) { if (FI->isUnnamedBitfield()) @@ -2475,7 +2572,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // the initializer list. if (RT->getDecl()->isUnion()) { FieldIndex = 0; - if (!VerifyOnly) { + if (StructuredList) { FieldDecl *CurrentField = StructuredList->getInitializedFieldInUnion(); if (CurrentField && !declaresSameEntity(CurrentField, *Field)) { assert(StructuredList->getNumInits() == 1 @@ -2484,13 +2581,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, Expr *ExistingInit = StructuredList->getInit(0); if (ExistingInit) { // We're about to throw away an initializer, emit warning. - SemaRef.Diag(D->getFieldLoc(), - diag::warn_initializer_overrides) - << D->getSourceRange(); - SemaRef.Diag(ExistingInit->getBeginLoc(), - diag::note_previous_initializer) - << /*FIXME:has side effects=*/0 - << ExistingInit->getSourceRange(); + diagnoseInitOverride( + ExistingInit, SourceRange(D->getBeginLoc(), DIE->getEndLoc())); } // remove existing initializer @@ -2513,16 +2605,63 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, return true; } - if (!VerifyOnly) { - // Update the designator with the field declaration. - D->setField(*Field); + // C++20 [dcl.init.list]p3: + // The ordered identifiers in the designators of the designated- + // initializer-list shall form a subsequence of the ordered identifiers + // in the direct non-static data members of T. + // + // Note that this is not a condition on forming the aggregate + // initialization, only on actually performing initialization, + // so it is not checked in VerifyOnly mode. + // + // FIXME: This is the only reordering diagnostic we produce, and it only + // catches cases where we have a top-level field designator that jumps + // backwards. This is the only such case that is reachable in an + // otherwise-valid C++20 program, so is the only case that's required for + // conformance, but for consistency, we should diagnose all the other + // cases where a designator takes us backwards too. + if (IsFirstDesignator && !VerifyOnly && SemaRef.getLangOpts().CPlusPlus && + NextField && + (*NextField == RT->getDecl()->field_end() || + (*NextField)->getFieldIndex() > Field->getFieldIndex() + 1)) { + // Find the field that we just initialized. + FieldDecl *PrevField = nullptr; + for (auto FI = RT->getDecl()->field_begin(); + FI != RT->getDecl()->field_end(); ++FI) { + if (FI->isUnnamedBitfield()) + continue; + if (*NextField != RT->getDecl()->field_end() && + declaresSameEntity(*FI, **NextField)) + break; + PrevField = *FI; + } - // Make sure that our non-designated initializer list has space - // for a subobject corresponding to this field. - if (FieldIndex >= StructuredList->getNumInits()) - StructuredList->resizeInits(SemaRef.Context, FieldIndex + 1); + if (PrevField && + PrevField->getFieldIndex() > KnownField->getFieldIndex()) { + SemaRef.Diag(DIE->getBeginLoc(), diag::ext_designated_init_reordered) + << KnownField << PrevField << DIE->getSourceRange(); + + unsigned OldIndex = NumBases + PrevField->getFieldIndex(); + if (StructuredList && OldIndex <= StructuredList->getNumInits()) { + if (Expr *PrevInit = StructuredList->getInit(OldIndex)) { + SemaRef.Diag(PrevInit->getBeginLoc(), + diag::note_previous_field_init) + << PrevField << PrevInit->getSourceRange(); + } + } + } } + + // Update the designator with the field declaration. + if (!VerifyOnly) + D->setField(*Field); + + // Make sure that our non-designated initializer list has space + // for a subobject corresponding to this field. + if (StructuredList && FieldIndex >= StructuredList->getNumInits()) + StructuredList->resizeInits(SemaRef.Context, FieldIndex + 1); + // This designator names a flexible array member. if (Field->getType()->isIncompleteArrayType()) { bool Invalid = false; @@ -2707,7 +2846,13 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, DesignatedEndIndex.setIsUnsigned(true); } - if (!VerifyOnly && StructuredList->isStringLiteralInit()) { + bool IsStringLiteralInitUpdate = + StructuredList && StructuredList->isStringLiteralInit(); + if (IsStringLiteralInitUpdate && VerifyOnly) { + // We're just verifying an update to a string literal init. We don't need + // to split the string up into individual characters to do that. + StructuredList = nullptr; + } else if (IsStringLiteralInitUpdate) { // We're modifying a string literal init; we have to decompose the string // so we can modify the individual characters. ASTContext &Context = SemaRef.Context; @@ -2767,7 +2912,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // Make sure that our non-designated initializer list has space // for a subobject corresponding to this array element. - if (!VerifyOnly && + if (StructuredList && DesignatedEndIndex.getZExtValue() >= StructuredList->getNumInits()) StructuredList->resizeInits(SemaRef.Context, DesignatedEndIndex.getZExtValue() + 1); @@ -2829,12 +2974,11 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, unsigned StructuredIndex, SourceRange InitRange, bool IsFullyOverwritten) { - if (VerifyOnly) - return nullptr; // No structured list in verification-only mode. - Expr *ExistingInit = nullptr; if (!StructuredList) - ExistingInit = SyntacticToSemantic.lookup(IList); - else if (StructuredIndex < StructuredList->getNumInits()) + return nullptr; + + Expr *ExistingInit = nullptr; + if (StructuredIndex < StructuredList->getNumInits()) ExistingInit = StructuredList->getInit(StructuredIndex); if (InitListExpr *Result = dyn_cast_or_null<InitListExpr>(ExistingInit)) @@ -2853,21 +2997,46 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, // We are creating an initializer list that initializes the // subobjects of the current object, but there was already an // initialization that completely initialized the current - // subobject, e.g., by a compound literal: + // subobject: // // struct X { int a, b; }; + // struct X xs[] = { [0] = { 1, 2 }, [0].b = 3 }; + // + // Here, xs[0].a == 1 and xs[0].b == 3, since the second, + // designated initializer overwrites the [0].b initializer + // from the prior initialization. + // + // When the existing initializer is an expression rather than an + // initializer list, we cannot decompose and update it in this way. + // For example: + // // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 }; // - // Here, xs[0].a == 0 and xs[0].b == 3, since the second, - // designated initializer re-initializes the whole - // subobject [0], overwriting previous initializers. - SemaRef.Diag(InitRange.getBegin(), - diag::warn_subobject_initializer_overrides) - << InitRange; - SemaRef.Diag(ExistingInit->getBeginLoc(), diag::note_previous_initializer) - << /*FIXME:has side effects=*/0 << ExistingInit->getSourceRange(); + // This case is handled by CheckDesignatedInitializer. + diagnoseInitOverride(ExistingInit, InitRange); } + unsigned ExpectedNumInits = 0; + if (Index < IList->getNumInits()) { + if (auto *Init = dyn_cast_or_null<InitListExpr>(IList->getInit(Index))) + ExpectedNumInits = Init->getNumInits(); + else + ExpectedNumInits = IList->getNumInits() - Index; + } + + InitListExpr *Result = + createInitListExpr(CurrentObjectType, InitRange, ExpectedNumInits); + + // Link this new initializer list into the structured initializer + // lists. + StructuredList->updateInit(SemaRef.Context, StructuredIndex, Result); + return Result; +} + +InitListExpr * +InitListChecker::createInitListExpr(QualType CurrentObjectType, + SourceRange InitRange, + unsigned ExpectedNumInits) { InitListExpr *Result = new (SemaRef.Context) InitListExpr(SemaRef.Context, InitRange.getBegin(), None, @@ -2880,17 +3049,6 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, // Pre-allocate storage for the structured initializer list. unsigned NumElements = 0; - unsigned NumInits = 0; - bool GotNumInits = false; - if (!StructuredList) { - NumInits = IList->getNumInits(); - GotNumInits = true; - } else if (Index < IList->getNumInits()) { - if (InitListExpr *SubList = dyn_cast<InitListExpr>(IList->getInit(Index))) { - NumInits = SubList->getNumInits(); - GotNumInits = true; - } - } if (const ArrayType *AType = SemaRef.Context.getAsArrayType(CurrentObjectType)) { @@ -2898,30 +3056,17 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, NumElements = CAType->getSize().getZExtValue(); // Simple heuristic so that we don't allocate a very large // initializer with many empty entries at the end. - if (GotNumInits && NumElements > NumInits) + if (NumElements > ExpectedNumInits) NumElements = 0; } - } else if (const VectorType *VType = CurrentObjectType->getAs<VectorType>()) + } else if (const VectorType *VType = CurrentObjectType->getAs<VectorType>()) { NumElements = VType->getNumElements(); - else if (const RecordType *RType = CurrentObjectType->getAs<RecordType>()) { - RecordDecl *RDecl = RType->getDecl(); - if (RDecl->isUnion()) - NumElements = 1; - else - NumElements = std::distance(RDecl->field_begin(), RDecl->field_end()); + } else if (CurrentObjectType->isRecordType()) { + NumElements = numStructUnionElements(CurrentObjectType); } Result->reserveInits(SemaRef.Context, NumElements); - // Link this new initializer list into the structured initializer - // lists. - if (StructuredList) - StructuredList->updateInit(SemaRef.Context, StructuredIndex, Result); - else { - Result->setSyntacticForm(IList); - SyntacticToSemantic[IList] = Result; - } - return Result; } @@ -2937,24 +3082,23 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList, if (Expr *PrevInit = StructuredList->updateInit(SemaRef.Context, StructuredIndex, expr)) { // This initializer overwrites a previous initializer. Warn. - // We need to check on source range validity because the previous - // initializer does not have to be an explicit initializer. - // struct P { int a, b; }; - // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 }; - // There is an overwrite taking place because the first braced initializer - // list "{ .a = 2 }' already provides value for .p.b (which is zero). - if (PrevInit->getSourceRange().isValid()) { - SemaRef.Diag(expr->getBeginLoc(), diag::warn_initializer_overrides) - << expr->getSourceRange(); - - SemaRef.Diag(PrevInit->getBeginLoc(), diag::note_previous_initializer) - << /*FIXME:has side effects=*/0 << PrevInit->getSourceRange(); - } + diagnoseInitOverride(PrevInit, expr->getSourceRange()); } ++StructuredIndex; } +/// Determine whether we can perform aggregate initialization for the purposes +/// of overload resolution. +bool Sema::CanPerformAggregateInitializationForOverloadResolution( + const InitializedEntity &Entity, InitListExpr *From) { + QualType Type = Entity.getType(); + InitListChecker Check(*this, Entity, From, Type, /*VerifyOnly=*/true, + /*TreatUnavailableAsInvalid=*/false, + /*InOverloadResolution=*/true); + return !Check.HadError(); +} + /// Check that the given Index expression is a valid array designator /// value. This is essentially just a wrapper around /// VerifyIntegerConstantExpression that also checks for negative values @@ -2980,7 +3124,7 @@ CheckArrayDesignatorExpr(Sema &S, Expr *Index, llvm::APSInt &Value) { } ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, - SourceLocation Loc, + SourceLocation EqualOrColonLoc, bool GNUSyntax, ExprResult Init) { typedef DesignatedInitExpr::Designator ASTDesignator; @@ -3065,17 +3209,9 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, // Clear out the expressions within the designation. Desig.ClearExprs(*this); - DesignatedInitExpr *DIE - = DesignatedInitExpr::Create(Context, - Designators, - InitExpressions, Loc, GNUSyntax, - Init.getAs<Expr>()); - - if (!getLangOpts().C99) - Diag(DIE->getBeginLoc(), diag::ext_designated_init) - << DIE->getSourceRange(); - - return DIE; + return DesignatedInitExpr::Create(Context, Designators, InitExpressions, + EqualOrColonLoc, GNUSyntax, + Init.getAs<Expr>()); } //===----------------------------------------------------------------------===// @@ -3691,9 +3827,10 @@ static bool TryInitializerListConstruction(Sema &S, // Try initializing a temporary array from the init list. QualType ArrayType = S.Context.getConstantArrayType( - E.withConst(), llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()), - List->getNumInits()), - clang::ArrayType::Normal, 0); + E.withConst(), + llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()), + List->getNumInits()), + nullptr, clang::ArrayType::Normal, 0); InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(ArrayType); InitializationKind Kind = InitializationKind::CreateDirectList( @@ -4070,7 +4207,7 @@ static void TryReferenceListInitialization(Sema &S, } QualType DestType = Entity.getType(); - QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType(); + QualType cv1T1 = DestType->castAs<ReferenceType>()->getPointeeType(); Qualifiers T1Quals; QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals); @@ -4092,10 +4229,10 @@ static void TryReferenceListInitialization(Sema &S, return; SourceLocation DeclLoc = Initializer->getBeginLoc(); - bool dummy1, dummy2, dummy3; + bool dummy1, dummy2, dummy3, dummy4; Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, dummy1, - dummy2, dummy3); + dummy2, dummy3, dummy4); if (RefRelationship >= Sema::Ref_Related) { // Try to bind the reference here. TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1, @@ -4327,7 +4464,7 @@ static OverloadingResult TryRefInitWithConversionFunction( Expr *Initializer, bool AllowRValues, bool IsLValueRef, InitializationSequence &Sequence) { QualType DestType = Entity.getType(); - QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType(); + QualType cv1T1 = DestType->castAs<ReferenceType>()->getPointeeType(); QualType T1 = cv1T1.getUnqualifiedType(); QualType cv2T2 = Initializer->getType(); QualType T2 = cv2T2.getUnqualifiedType(); @@ -4335,13 +4472,15 @@ static OverloadingResult TryRefInitWithConversionFunction( bool DerivedToBase; bool ObjCConversion; bool ObjCLifetimeConversion; - assert(!S.CompareReferenceRelationship(Initializer->getBeginLoc(), T1, T2, - DerivedToBase, ObjCConversion, - ObjCLifetimeConversion) && + bool FunctionConversion; + assert(!S.CompareReferenceRelationship( + Initializer->getBeginLoc(), T1, T2, DerivedToBase, ObjCConversion, + ObjCLifetimeConversion, FunctionConversion) && "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. @@ -4468,10 +4607,11 @@ static OverloadingResult TryRefInitWithConversionFunction( bool NewDerivedToBase = false; bool NewObjCConversion = false; bool NewObjCLifetimeConversion = false; - Sema::ReferenceCompareResult NewRefRelationship - = S.CompareReferenceRelationship(DeclLoc, T1, cv3T3, - NewDerivedToBase, NewObjCConversion, - NewObjCLifetimeConversion); + bool NewFunctionConversion = false; + Sema::ReferenceCompareResult NewRefRelationship = + S.CompareReferenceRelationship( + DeclLoc, T1, cv3T3, NewDerivedToBase, NewObjCConversion, + NewObjCLifetimeConversion, NewFunctionConversion); // Add the final conversion sequence, if necessary. if (NewRefRelationship == Sema::Ref_Incompatible) { @@ -4505,6 +4645,8 @@ static OverloadingResult TryRefInitWithConversionFunction( Sequence.AddDerivedToBaseCastStep(cv1T1, VK); else if (NewObjCConversion) Sequence.AddObjCObjectConversionStep(cv1T1); + else if (NewFunctionConversion) + Sequence.AddQualificationConversionStep(cv1T1, VK); return OR_Success; } @@ -4520,7 +4662,7 @@ static void TryReferenceInitialization(Sema &S, Expr *Initializer, InitializationSequence &Sequence) { QualType DestType = Entity.getType(); - QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType(); + QualType cv1T1 = DestType->castAs<ReferenceType>()->getPointeeType(); Qualifiers T1Quals; QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals); QualType cv2T2 = Initializer->getType(); @@ -4564,10 +4706,11 @@ static void TryReferenceInitializationCore(Sema &S, 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); + Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship( + DeclLoc, cv1T1, cv2T2, DerivedToBase, ObjCConversion, + ObjCLifetimeConversion, FunctionConversion); // C++0x [dcl.init.ref]p5: // A reference to type "cv1 T1" is initialized by an expression of type @@ -4598,6 +4741,8 @@ static void TryReferenceInitializationCore(Sema &S, Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue); else if (ObjCConversion) Sequence.AddObjCObjectConversionStep(cv1T1); + else if (FunctionConversion) + Sequence.AddQualificationConversionStep(cv1T1, VK_LValue); // We only create a temporary here when binding a reference to a // bit-field or vector element. Those cases are't supposed to be @@ -6233,8 +6378,11 @@ PerformConstructorInitialization(Sema &S, // the definition for completely trivial constructors. assert(Constructor->getParent() && "No parent class for constructor."); if (Constructor->isDefaulted() && Constructor->isDefaultConstructor() && - Constructor->isTrivial() && !Constructor->isUsed(false)) - S.DefineImplicitDefaultConstructor(Loc, Constructor); + Constructor->isTrivial() && !Constructor->isUsed(false)) { + S.runWithSufficientStackSpace(Loc, [&] { + S.DefineImplicitDefaultConstructor(Loc, Constructor); + }); + } } ExprResult CurInit((Expr *)nullptr); @@ -6505,6 +6653,7 @@ struct IndirectLocalPathEntry { VarInit, LValToRVal, LifetimeBoundCall, + GslPointerInit } Kind; Expr *E; const Decl *D = nullptr; @@ -6543,11 +6692,138 @@ static bool pathContainsInit(IndirectLocalPath &Path) { static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, Expr *Init, LocalVisitor Visit, - bool RevisitSubinits); + bool RevisitSubinits, + bool EnableLifetimeWarnings); static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, Expr *Init, ReferenceKind RK, - LocalVisitor Visit); + LocalVisitor Visit, + bool EnableLifetimeWarnings); + +template <typename T> static bool isRecordWithAttr(QualType Type) { + if (auto *RD = Type->getAsCXXRecordDecl()) + return RD->hasAttr<T>(); + return false; +} + +// Decl::isInStdNamespace will return false for iterators in some STL +// implementations due to them being defined in a namespace outside of the std +// namespace. +static bool isInStlNamespace(const Decl *D) { + const DeclContext *DC = D->getDeclContext(); + if (!DC) + return false; + if (const auto *ND = dyn_cast<NamespaceDecl>(DC)) + if (const IdentifierInfo *II = ND->getIdentifier()) { + StringRef Name = II->getName(); + if (Name.size() >= 2 && Name.front() == '_' && + (Name[1] == '_' || isUppercase(Name[1]))) + return true; + } + + return DC->isStdNamespace(); +} + +static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) { + if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee)) + if (isRecordWithAttr<PointerAttr>(Conv->getConversionType())) + return true; + if (!isInStlNamespace(Callee->getParent())) + return false; + if (!isRecordWithAttr<PointerAttr>(Callee->getThisObjectType()) && + !isRecordWithAttr<OwnerAttr>(Callee->getThisObjectType())) + return false; + if (Callee->getReturnType()->isPointerType() || + isRecordWithAttr<PointerAttr>(Callee->getReturnType())) { + if (!Callee->getIdentifier()) + return false; + return llvm::StringSwitch<bool>(Callee->getName()) + .Cases("begin", "rbegin", "cbegin", "crbegin", true) + .Cases("end", "rend", "cend", "crend", true) + .Cases("c_str", "data", "get", true) + // Map and set types. + .Cases("find", "equal_range", "lower_bound", "upper_bound", true) + .Default(false); + } else if (Callee->getReturnType()->isReferenceType()) { + if (!Callee->getIdentifier()) { + auto OO = Callee->getOverloadedOperator(); + return OO == OverloadedOperatorKind::OO_Subscript || + OO == OverloadedOperatorKind::OO_Star; + } + return llvm::StringSwitch<bool>(Callee->getName()) + .Cases("front", "back", "at", "top", "value", true) + .Default(false); + } + return false; +} + +static bool shouldTrackFirstArgument(const FunctionDecl *FD) { + if (!FD->getIdentifier() || FD->getNumParams() != 1) + return false; + const auto *RD = FD->getParamDecl(0)->getType()->getPointeeCXXRecordDecl(); + if (!FD->isInStdNamespace() || !RD || !RD->isInStdNamespace()) + return false; + if (!isRecordWithAttr<PointerAttr>(QualType(RD->getTypeForDecl(), 0)) && + !isRecordWithAttr<OwnerAttr>(QualType(RD->getTypeForDecl(), 0))) + return false; + if (FD->getReturnType()->isPointerType() || + isRecordWithAttr<PointerAttr>(FD->getReturnType())) { + return llvm::StringSwitch<bool>(FD->getName()) + .Cases("begin", "rbegin", "cbegin", "crbegin", true) + .Cases("end", "rend", "cend", "crend", true) + .Case("data", true) + .Default(false); + } else if (FD->getReturnType()->isReferenceType()) { + return llvm::StringSwitch<bool>(FD->getName()) + .Cases("get", "any_cast", true) + .Default(false); + } + return false; +} + +static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call, + LocalVisitor Visit) { + auto VisitPointerArg = [&](const Decl *D, Expr *Arg) { + // 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}); + if (Arg->isGLValue()) + visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding, + Visit, + /*EnableLifetimeWarnings=*/true); + else + visitLocalsRetainedByInitializer(Path, Arg, Visit, true, + /*EnableLifetimeWarnings=*/true); + Path.pop_back(); + }; + + if (auto *MCE = dyn_cast<CXXMemberCallExpr>(Call)) { + const auto *MD = cast_or_null<CXXMethodDecl>(MCE->getDirectCallee()); + if (MD && shouldTrackImplicitObjectArg(MD)) + VisitPointerArg(MD, MCE->getImplicitObjectArgument()); + 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)); + return; + } else if (auto *CE = dyn_cast<CallExpr>(Call)) { + FunctionDecl *Callee = CE->getDirectCallee(); + if (Callee && shouldTrackFirstArgument(Callee)) + VisitPointerArg(Callee, CE->getArg(0)); + return; + } + + if (auto *CCE = dyn_cast<CXXConstructExpr>(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]); + } +} static bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) { const TypeSourceInfo *TSI = FD->getTypeSourceInfo(); @@ -6594,9 +6870,11 @@ static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call, Path.push_back({IndirectLocalPathEntry::LifetimeBoundCall, Arg, D}); if (Arg->isGLValue()) visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding, - Visit); + Visit, + /*EnableLifetimeWarnings=*/false); else - visitLocalsRetainedByInitializer(Path, Arg, Visit, true); + visitLocalsRetainedByInitializer(Path, Arg, Visit, true, + /*EnableLifetimeWarnings=*/false); Path.pop_back(); }; @@ -6615,7 +6893,8 @@ static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call, /// glvalue expression \c Init. static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, Expr *Init, ReferenceKind RK, - LocalVisitor Visit) { + LocalVisitor Visit, + bool EnableLifetimeWarnings) { RevertToOldSizeRAII RAII(Path); // Walk past any constructs which we can lifetime-extend across. @@ -6652,7 +6931,8 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, else // We can't lifetime extend through this but we might still find some // retained temporaries. - return visitLocalsRetainedByInitializer(Path, Init, Visit, true); + return visitLocalsRetainedByInitializer(Path, Init, Visit, true, + EnableLifetimeWarnings); } // Step into CXXDefaultInitExprs so we can diagnose cases where a @@ -6667,11 +6947,14 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) { if (Visit(Path, Local(MTE), RK)) visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(), Visit, - true); + true, EnableLifetimeWarnings); } - if (isa<CallExpr>(Init)) + if (isa<CallExpr>(Init)) { + if (EnableLifetimeWarnings) + handleGslAnnotatedTypes(Path, Init, Visit); return visitLifetimeBoundArguments(Path, Init, Visit); + } switch (Init->getStmtClass()) { case Stmt::DeclRefExprClass: { @@ -6690,7 +6973,8 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, } else if (VD->getInit() && !isVarOnPath(Path, VD)) { Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD}); visitLocalsRetainedByReferenceBinding(Path, VD->getInit(), - RK_ReferenceBinding, Visit); + RK_ReferenceBinding, Visit, + EnableLifetimeWarnings); } } break; @@ -6702,13 +6986,15 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, // handling all sorts of rvalues passed to a unary operator. const UnaryOperator *U = cast<UnaryOperator>(Init); if (U->getOpcode() == UO_Deref) - visitLocalsRetainedByInitializer(Path, U->getSubExpr(), Visit, true); + visitLocalsRetainedByInitializer(Path, U->getSubExpr(), Visit, true, + EnableLifetimeWarnings); break; } case Stmt::OMPArraySectionExprClass: { - visitLocalsRetainedByInitializer( - Path, cast<OMPArraySectionExpr>(Init)->getBase(), Visit, true); + visitLocalsRetainedByInitializer(Path, + cast<OMPArraySectionExpr>(Init)->getBase(), + Visit, true, EnableLifetimeWarnings); break; } @@ -6716,9 +7002,11 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, case Stmt::BinaryConditionalOperatorClass: { auto *C = cast<AbstractConditionalOperator>(Init); if (!C->getTrueExpr()->getType()->isVoidType()) - visitLocalsRetainedByReferenceBinding(Path, C->getTrueExpr(), RK, Visit); + visitLocalsRetainedByReferenceBinding(Path, C->getTrueExpr(), RK, Visit, + EnableLifetimeWarnings); if (!C->getFalseExpr()->getType()->isVoidType()) - visitLocalsRetainedByReferenceBinding(Path, C->getFalseExpr(), RK, Visit); + visitLocalsRetainedByReferenceBinding(Path, C->getFalseExpr(), RK, Visit, + EnableLifetimeWarnings); break; } @@ -6733,7 +7021,8 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, /// the prvalue expression \c Init. static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, Expr *Init, LocalVisitor Visit, - bool RevisitSubinits) { + bool RevisitSubinits, + bool EnableLifetimeWarnings) { RevertToOldSizeRAII RAII(Path); Expr *Old; @@ -6773,15 +7062,17 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, if (VD && VD->getType().isConstQualified() && VD->getInit() && !isVarOnPath(Path, VD)) { Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD}); - visitLocalsRetainedByInitializer(Path, VD->getInit(), Visit, true); + visitLocalsRetainedByInitializer(Path, VD->getInit(), Visit, true, + EnableLifetimeWarnings); } } else if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L)) { if (MTE->getType().isConstQualified()) visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(), - Visit, true); + Visit, true, + EnableLifetimeWarnings); } return false; - }); + }, EnableLifetimeWarnings); // We assume that objects can be retained by pointers cast to integers, // but not if the integer is cast to floating-point type or to _Complex. @@ -6811,7 +7102,8 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, // lvalue. Path.push_back({IndirectLocalPathEntry::AddressOf, CE}); return visitLocalsRetainedByReferenceBinding(Path, CE->getSubExpr(), - RK_ReferenceBinding, Visit); + RK_ReferenceBinding, Visit, + EnableLifetimeWarnings); default: return; @@ -6826,7 +7118,8 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, // lifetime of the array exactly like binding a reference to a temporary. if (auto *ILE = dyn_cast<CXXStdInitializerListExpr>(Init)) return visitLocalsRetainedByReferenceBinding(Path, ILE->getSubExpr(), - RK_StdInitializerList, Visit); + RK_StdInitializerList, Visit, + EnableLifetimeWarnings); if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { // We already visited the elements of this initializer list while @@ -6837,12 +7130,14 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, if (ILE->isTransparent()) return visitLocalsRetainedByInitializer(Path, ILE->getInit(0), Visit, - RevisitSubinits); + RevisitSubinits, + EnableLifetimeWarnings); if (ILE->getType()->isArrayType()) { for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I) visitLocalsRetainedByInitializer(Path, ILE->getInit(I), Visit, - RevisitSubinits); + RevisitSubinits, + EnableLifetimeWarnings); return; } @@ -6855,12 +7150,14 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, if (RD->isUnion() && ILE->getInitializedFieldInUnion() && ILE->getInitializedFieldInUnion()->getType()->isReferenceType()) visitLocalsRetainedByReferenceBinding(Path, ILE->getInit(0), - RK_ReferenceBinding, Visit); + RK_ReferenceBinding, Visit, + EnableLifetimeWarnings); else { unsigned Index = 0; for (; Index < RD->getNumBases() && Index < ILE->getNumInits(); ++Index) visitLocalsRetainedByInitializer(Path, ILE->getInit(Index), Visit, - RevisitSubinits); + RevisitSubinits, + EnableLifetimeWarnings); for (const auto *I : RD->fields()) { if (Index >= ILE->getNumInits()) break; @@ -6869,13 +7166,15 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, Expr *SubInit = ILE->getInit(Index); if (I->getType()->isReferenceType()) visitLocalsRetainedByReferenceBinding(Path, SubInit, - RK_ReferenceBinding, Visit); + RK_ReferenceBinding, Visit, + EnableLifetimeWarnings); else // This might be either aggregate-initialization of a member or // initialization of a std::initializer_list object. Regardless, // we should recursively lifetime-extend that initializer. visitLocalsRetainedByInitializer(Path, SubInit, Visit, - RevisitSubinits); + RevisitSubinits, + EnableLifetimeWarnings); ++Index; } } @@ -6891,14 +7190,18 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, continue; if (E->isGLValue()) visitLocalsRetainedByReferenceBinding(Path, E, RK_ReferenceBinding, - Visit); + Visit, EnableLifetimeWarnings); else - visitLocalsRetainedByInitializer(Path, E, Visit, true); + visitLocalsRetainedByInitializer(Path, E, Visit, true, + EnableLifetimeWarnings); } } - if (isa<CallExpr>(Init) || isa<CXXConstructExpr>(Init)) + if (isa<CallExpr>(Init) || isa<CXXConstructExpr>(Init)) { + if (EnableLifetimeWarnings) + handleGslAnnotatedTypes(Path, Init, Visit); return visitLifetimeBoundArguments(Path, Init, Visit); + } switch (Init->getStmtClass()) { case Stmt::UnaryOperatorClass: { @@ -6914,7 +7217,8 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, Path.push_back({IndirectLocalPathEntry::AddressOf, UO}); visitLocalsRetainedByReferenceBinding(Path, UO->getSubExpr(), - RK_ReferenceBinding, Visit); + RK_ReferenceBinding, Visit, + EnableLifetimeWarnings); } break; } @@ -6927,9 +7231,11 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, break; if (BO->getLHS()->getType()->isPointerType()) - visitLocalsRetainedByInitializer(Path, BO->getLHS(), Visit, true); + visitLocalsRetainedByInitializer(Path, BO->getLHS(), Visit, true, + EnableLifetimeWarnings); else if (BO->getRHS()->getType()->isPointerType()) - visitLocalsRetainedByInitializer(Path, BO->getRHS(), Visit, true); + visitLocalsRetainedByInitializer(Path, BO->getRHS(), Visit, true, + EnableLifetimeWarnings); break; } @@ -6939,9 +7245,11 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, // In C++, we can have a throw-expression operand, which has 'void' type // and isn't interesting from a lifetime perspective. if (!C->getTrueExpr()->getType()->isVoidType()) - visitLocalsRetainedByInitializer(Path, C->getTrueExpr(), Visit, true); + visitLocalsRetainedByInitializer(Path, C->getTrueExpr(), Visit, true, + EnableLifetimeWarnings); if (!C->getFalseExpr()->getType()->isVoidType()) - visitLocalsRetainedByInitializer(Path, C->getFalseExpr(), Visit, true); + visitLocalsRetainedByInitializer(Path, C->getFalseExpr(), Visit, true, + EnableLifetimeWarnings); break; } @@ -6980,18 +7288,33 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I, case IndirectLocalPathEntry::AddressOf: case IndirectLocalPathEntry::LValToRVal: case IndirectLocalPathEntry::LifetimeBoundCall: + case IndirectLocalPathEntry::GslPointerInit: // These exist primarily to mark the path as not permitting or // supporting lifetime extension. break; - case IndirectLocalPathEntry::DefaultInit: case IndirectLocalPathEntry::VarInit: + if (cast<VarDecl>(Path[I].D)->isImplicit()) + return SourceRange(); + LLVM_FALLTHROUGH; + case IndirectLocalPathEntry::DefaultInit: return Path[I].E->getSourceRange(); } } return E->getSourceRange(); } +static bool pathOnlyInitializesGslPointer(IndirectLocalPath &Path) { + for (auto It = Path.rbegin(), End = Path.rend(); It != End; ++It) { + if (It->Kind == IndirectLocalPathEntry::VarInit) + continue; + if (It->Kind == IndirectLocalPathEntry::AddressOf) + continue; + return It->Kind == IndirectLocalPathEntry::GslPointerInit; + } + return false; +} + void Sema::checkInitializerLifetime(const InitializedEntity &Entity, Expr *Init) { LifetimeResult LR = getEntityLifetime(&Entity); @@ -7008,12 +7331,36 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, SourceRange DiagRange = nextPathEntryRange(Path, 0, L); SourceLocation DiagLoc = DiagRange.getBegin(); + auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L); + + bool IsGslPtrInitWithGslTempOwner = false; + bool IsLocalGslOwner = false; + if (pathOnlyInitializesGslPointer(Path)) { + if (isa<DeclRefExpr>(L)) { + // We do not want to follow the references when returning a pointer originating + // from a local owner to avoid the following false positive: + // int &p = *localUniquePtr; + // someContainer.add(std::move(localUniquePtr)); + // return p; + IsLocalGslOwner = isRecordWithAttr<OwnerAttr>(L->getType()); + if (pathContainsInit(Path) || !IsLocalGslOwner) + return false; + } else { + IsGslPtrInitWithGslTempOwner = MTE && !MTE->getExtendingDecl() && + isRecordWithAttr<OwnerAttr>(MTE->getType()); + // Skipping a chain of initializing gsl::Pointer annotated objects. + // We are looking only for the final source to find out if it was + // a local or temporary owner or the address of a local variable/param. + if (!IsGslPtrInitWithGslTempOwner) + return true; + } + } + switch (LK) { case LK_FullExpression: llvm_unreachable("already handled this"); case LK_Extended: { - auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L); if (!MTE) { // The initialized entity has lifetime beyond the full-expression, // and the local entity does too, so don't warn. @@ -7023,6 +7370,11 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, return false; } + if (IsGslPtrInitWithGslTempOwner && DiagLoc.isValid()) { + Diag(DiagLoc, diag::warn_dangling_lifetime_pointer) << DiagRange; + return false; + } + // Lifetime-extend the temporary. if (Path.empty()) { // Update the storage duration of the materialized temporary. @@ -7064,6 +7416,14 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, // temporary, the program is ill-formed. if (auto *ExtendingDecl = ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) { + if (IsGslPtrInitWithGslTempOwner) { + Diag(DiagLoc, diag::warn_dangling_lifetime_pointer_member) + << ExtendingDecl << DiagRange; + Diag(ExtendingDecl->getLocation(), + diag::note_ref_or_ptr_member_declared_here) + << true; + return false; + } bool IsSubobjectMember = ExtendingEntity != &Entity; Diag(DiagLoc, shouldLifetimeExtendThroughPath(Path) ? diag::err_dangling_member @@ -7094,6 +7454,11 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, if (pathContainsInit(Path)) return false; + // Suppress false positives for code like the one below: + // Ctor(unique_ptr<T> up) : member(*up), member2(move(up)) {} + if (IsLocalGslOwner && pathOnlyInitializesGslPointer(Path)) + return false; + auto *DRE = dyn_cast<DeclRefExpr>(L); auto *VD = DRE ? dyn_cast<VarDecl>(DRE->getDecl()) : nullptr; if (!VD) { @@ -7104,7 +7469,7 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, if (auto *Member = ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) { - bool IsPointer = Member->getType()->isAnyPointerType(); + bool IsPointer = !Member->getType()->isReferenceType(); Diag(DiagLoc, IsPointer ? diag::warn_init_ptr_member_to_parameter_addr : diag::warn_bind_ref_member_to_parameter) << Member << VD << isa<ParmVarDecl>(VD) << DiagRange; @@ -7118,10 +7483,13 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, case LK_New: if (isa<MaterializeTemporaryExpr>(L)) { - Diag(DiagLoc, RK == RK_ReferenceBinding - ? diag::warn_new_dangling_reference - : diag::warn_new_dangling_initializer_list) - << !Entity.getParent() << DiagRange; + if (IsGslPtrInitWithGslTempOwner) + Diag(DiagLoc, diag::warn_dangling_lifetime_pointer) << DiagRange; + else + Diag(DiagLoc, RK == RK_ReferenceBinding + ? diag::warn_new_dangling_reference + : diag::warn_new_dangling_initializer_list) + << !Entity.getParent() << DiagRange; } else { // We can't determine if the allocation outlives the local declaration. return false; @@ -7164,7 +7532,8 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, break; case IndirectLocalPathEntry::LifetimeBoundCall: - // FIXME: Consider adding a note for this. + case IndirectLocalPathEntry::GslPointerInit: + // FIXME: Consider adding a note for these. break; case IndirectLocalPathEntry::DefaultInit: { @@ -7189,12 +7558,16 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, return false; }; + bool EnableLifetimeWarnings = !getDiagnostics().isIgnored( + diag::warn_dangling_lifetime_pointer, SourceLocation()); llvm::SmallVector<IndirectLocalPathEntry, 8> Path; if (Init->isGLValue()) visitLocalsRetainedByReferenceBinding(Path, Init, RK_ReferenceBinding, - TemporaryVisitor); + TemporaryVisitor, + EnableLifetimeWarnings); else - visitLocalsRetainedByInitializer(Path, Init, TemporaryVisitor, false); + visitLocalsRetainedByInitializer(Path, Init, TemporaryVisitor, false, + EnableLifetimeWarnings); } static void DiagnoseNarrowingInInitList(Sema &S, @@ -7837,7 +8210,7 @@ ExprResult InitializationSequence::Perform(Sema &S, Ty = S.Context.getRValueReferenceType(Ty); else if ((*ResultType)->isLValueReferenceType()) Ty = S.Context.getLValueReferenceType(Ty, - (*ResultType)->getAs<LValueReferenceType>()->isSpelledAsLValue()); + (*ResultType)->castAs<LValueReferenceType>()->isSpelledAsLValue()); *ResultType = Ty; } @@ -8043,6 +8416,7 @@ ExprResult InitializationSequence::Perform(Sema &S, *ResultType = S.Context.getConstantArrayType( IncompleteDest->getElementType(), ConstantSource->getSize(), + ConstantSource->getSizeExpr(), ArrayType::Normal, 0); } } @@ -8108,7 +8482,7 @@ ExprResult InitializationSequence::Perform(Sema &S, // argument passing. assert(Step->Type->isSamplerT() && "Sampler initialization on non-sampler type."); - Expr *Init = CurInit.get(); + Expr *Init = CurInit.get()->IgnoreParens(); QualType SourceType = Init->getType(); // Case 1 if (Entity.isParameterKind()) { @@ -8285,7 +8659,7 @@ static void diagnoseListInit(Sema &S, const InitializedEntity &Entity, E.withConst(), llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()), InitList->getNumInits()), - clang::ArrayType::Normal, 0); + nullptr, clang::ArrayType::Normal, 0); InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(ArrayType); return diagnoseListInit(S, HiddenArray, InitList); @@ -8295,7 +8669,7 @@ static void diagnoseListInit(Sema &S, const InitializedEntity &Entity, // A list-initialization failure for a reference means that we tried to // create a temporary of the inner type (per [dcl.init.list]p3.6) and the // inner initialization failed. - QualType T = DestType->getAs<ReferenceType>()->getPointeeType(); + QualType T = DestType->castAs<ReferenceType>()->getPointeeType(); diagnoseListInit(S, InitializedEntity::InitializeTemporary(T), InitList); SourceLocation Loc = InitList->getBeginLoc(); if (auto *D = Entity.getDecl()) @@ -8652,7 +9026,7 @@ bool InitializationSequence::Diagnose(Sema &S, << InheritedFrom; RecordDecl *BaseDecl - = Entity.getBaseSpecifier()->getType()->getAs<RecordType>() + = Entity.getBaseSpecifier()->getType()->castAs<RecordType>() ->getDecl(); S.Diag(BaseDecl->getLocation(), diag::note_previous_decl) << S.Context.getTagDeclType(BaseDecl); diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 986524e6d56b..c6b19a0b195c 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -272,12 +272,11 @@ static bool isInInlineFunction(const DeclContext *DC) { return false; } -MangleNumberingContext * -Sema::getCurrentMangleNumberContext(const DeclContext *DC, - Decl *&ManglingContextDecl) { +std::tuple<MangleNumberingContext *, Decl *> +Sema::getCurrentMangleNumberContext(const DeclContext *DC) { // Compute the context for allocating mangling numbers in the current // expression, if the ABI requires them. - ManglingContextDecl = ExprEvalContexts.back().ManglingContextDecl; + Decl *ManglingContextDecl = ExprEvalContexts.back().ManglingContextDecl; enum ContextKind { Normal, @@ -325,22 +324,18 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC, if ((IsInNonspecializedTemplate && !(ManglingContextDecl && isa<ParmVarDecl>(ManglingContextDecl))) || isInInlineFunction(CurContext)) { - ManglingContextDecl = nullptr; while (auto *CD = dyn_cast<CapturedDecl>(DC)) DC = CD->getParent(); - return &Context.getManglingNumberContext(DC); + return std::make_tuple(&Context.getManglingNumberContext(DC), nullptr); } - ManglingContextDecl = nullptr; - return nullptr; + return std::make_tuple(nullptr, nullptr); } case StaticDataMember: // -- the initializers of nonspecialized static members of template classes - if (!IsInNonspecializedTemplate) { - ManglingContextDecl = nullptr; - return nullptr; - } + if (!IsInNonspecializedTemplate) + return std::make_tuple(nullptr, ManglingContextDecl); // Fall through to get the current context. LLVM_FALLTHROUGH; @@ -352,29 +347,24 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC, // -- the initializers of inline variables case VariableTemplate: // -- the initializers of templated variables - return &ExprEvalContexts.back().getMangleNumberingContext(Context); + return std::make_tuple( + &Context.getManglingNumberContext(ASTContext::NeedExtraManglingDecl, + ManglingContextDecl), + ManglingContextDecl); } llvm_unreachable("unexpected context"); } -MangleNumberingContext & -Sema::ExpressionEvaluationContextRecord::getMangleNumberingContext( - ASTContext &Ctx) { - assert(ManglingContextDecl && "Need to have a context declaration"); - if (!MangleNumbering) - MangleNumbering = Ctx.createMangleNumberingContext(); - return *MangleNumbering; -} - -CXXMethodDecl *Sema::startLambdaDefinition( - CXXRecordDecl *Class, SourceRange IntroducerRange, - TypeSourceInfo *MethodTypeInfo, SourceLocation EndLoc, - ArrayRef<ParmVarDecl *> Params, ConstexprSpecKind ConstexprKind, - Optional<std::pair<unsigned, Decl *>> Mangling) { +CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, + SourceRange IntroducerRange, + TypeSourceInfo *MethodTypeInfo, + SourceLocation EndLoc, + ArrayRef<ParmVarDecl *> Params, + ConstexprSpecKind ConstexprKind) { QualType MethodType = MethodTypeInfo->getType(); TemplateParameterList *TemplateParams = - getGenericLambdaTemplateParameterList(getCurLambda(), *this); + getGenericLambdaTemplateParameterList(getCurLambda(), *this); // If a lambda appears in a dependent context or is a generic lambda (has // template parameters) and has an 'auto' return type, deduce it to a // dependent type. @@ -407,6 +397,8 @@ CXXMethodDecl *Sema::startLambdaDefinition( MethodType, MethodTypeInfo, SC_None, /*isInline=*/true, ConstexprKind, EndLoc); Method->setAccess(AS_public); + if (!TemplateParams) + Class->addDecl(Method); // Temporarily set the lexical declaration context to the current // context, so that the Scope stack matches the lexical nesting. @@ -418,9 +410,10 @@ CXXMethodDecl *Sema::startLambdaDefinition( TemplateParams, Method) : nullptr; if (TemplateMethod) { - TemplateMethod->setLexicalDeclContext(CurContext); TemplateMethod->setAccess(AS_public); Method->setDescribedFunctionTemplate(TemplateMethod); + Class->addDecl(TemplateMethod); + TemplateMethod->setLexicalDeclContext(CurContext); } // Add parameters. @@ -433,19 +426,56 @@ CXXMethodDecl *Sema::startLambdaDefinition( P->setOwningFunction(Method); } + return Method; +} + +void Sema::handleLambdaNumbering( + CXXRecordDecl *Class, CXXMethodDecl *Method, + Optional<std::tuple<unsigned, bool, Decl *>> Mangling) { if (Mangling) { - Class->setLambdaMangling(Mangling->first, Mangling->second); - } else { + unsigned ManglingNumber; + bool HasKnownInternalLinkage; Decl *ManglingContextDecl; - if (MangleNumberingContext *MCtx = - getCurrentMangleNumberContext(Class->getDeclContext(), - ManglingContextDecl)) { - unsigned ManglingNumber = MCtx->getManglingNumber(Method); - Class->setLambdaMangling(ManglingNumber, ManglingContextDecl); - } + std::tie(ManglingNumber, HasKnownInternalLinkage, ManglingContextDecl) = + Mangling.getValue(); + Class->setLambdaMangling(ManglingNumber, ManglingContextDecl, + HasKnownInternalLinkage); + return; } - return Method; + auto getMangleNumberingContext = + [this](CXXRecordDecl *Class, + Decl *ManglingContextDecl) -> MangleNumberingContext * { + // Get mangle numbering context if there's any extra decl context. + if (ManglingContextDecl) + return &Context.getManglingNumberContext( + ASTContext::NeedExtraManglingDecl, ManglingContextDecl); + // Otherwise, from that lambda's decl context. + auto DC = Class->getDeclContext(); + while (auto *CD = dyn_cast<CapturedDecl>(DC)) + DC = CD->getParent(); + return &Context.getManglingNumberContext(DC); + }; + + MangleNumberingContext *MCtx; + Decl *ManglingContextDecl; + std::tie(MCtx, ManglingContextDecl) = + getCurrentMangleNumberContext(Class->getDeclContext()); + bool HasKnownInternalLinkage = false; + if (!MCtx && getLangOpts().CUDA) { + // Force lambda numbering in CUDA/HIP as we need to name lambdas following + // ODR. Both device- and host-compilation need to have a consistent naming + // on kernel functions. As lambdas are potential part of these `__global__` + // function names, they needs numbering following ODR. + MCtx = getMangleNumberingContext(Class, ManglingContextDecl); + assert(MCtx && "Retrieving mangle numbering context failed!"); + HasKnownInternalLinkage = true; + } + if (MCtx) { + unsigned ManglingNumber = MCtx->getManglingNumber(Method); + Class->setLambdaMangling(ManglingNumber, ManglingContextDecl, + HasKnownInternalLinkage); + } } void Sema::buildLambdaScope(LambdaScopeInfo *LSI, @@ -839,6 +869,8 @@ VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc, NewVD->setInitStyle(static_cast<VarDecl::InitializationStyle>(InitStyle)); NewVD->markUsed(Context); NewVD->setInit(Init); + if (NewVD->isParameterPack()) + getCurLambda()->LocalPacks.push_back(NewVD); return NewVD; } @@ -928,12 +960,12 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, // Check for unexpanded parameter packs in the method type. if (MethodTyInfo->getType()->containsUnexpandedParameterPack()) - ContainsUnexpandedParameterPack = true; + DiagnoseUnexpandedParameterPack(Intro.Range.getBegin(), MethodTyInfo, + UPPC_DeclarationType); } CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, MethodTyInfo, KnownDependent, Intro.Default); - CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params, ParamInfo.getDeclSpec().getConstexprSpecifier()); @@ -956,6 +988,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, if (getLangOpts().CUDA) CUDASetLambdaAttrs(Method); + // Number the lambda for linkage purposes if necessary. + handleLambdaNumbering(Class, Method); + // Introduce the function call operator as the current declaration context. PushDeclContext(CurScope, Method); @@ -1053,7 +1088,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, if (C->Init.get()->containsUnexpandedParameterPack() && !C->InitCaptureType.get()->getAs<PackExpansionType>()) - ContainsUnexpandedParameterPack = true; + DiagnoseUnexpandedParameterPack(C->Init.get(), UPPC_Initializer); unsigned InitStyle; switch (C->InitKind) { @@ -1184,7 +1219,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, } finishLambdaExplicitCaptures(LSI); - LSI->ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; + LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack; // Add lambda parameters into scope. addLambdaParameters(Intro.Captures, Method, CurScope); @@ -1639,8 +1674,9 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, ? CallOperator->getDescribedFunctionTemplate() : cast<Decl>(CallOperator); + // FIXME: Is this really the best choice? Keeping the lexical decl context + // set as CurContext seems more faithful to the source. TemplateOrNonTemplateCallOperatorDecl->setLexicalDeclContext(Class); - Class->addDecl(TemplateOrNonTemplateCallOperatorDecl); PopExpressionEvaluationContext(); @@ -1776,10 +1812,9 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, !CallOperator->isConstexpr() && !isa<CoroutineBodyStmt>(CallOperator->getBody()) && !Class->getDeclContext()->isDependentContext()) { - TentativeAnalysisScope DiagnosticScopeGuard(*this); CallOperator->setConstexprKind( - (CheckConstexprFunctionDecl(CallOperator) && - CheckConstexprFunctionBody(CallOperator, CallOperator->getBody())) + CheckConstexprFunctionDefinition(CallOperator, + CheckConstexprKind::CheckValid) ? CSK_constexpr : CSK_unspecified); } diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 8a24dd884a76..d56c5980237c 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -673,82 +673,160 @@ LLVM_DUMP_METHOD void LookupResult::dump() { D->dump(); } -/// When trying to resolve a function name, if the isOpenCLBuiltin function -/// defined in "OpenCLBuiltins.inc" returns a non-null <Index, Len>, then the -/// identifier is referencing an OpenCL builtin function. Thus, all its -/// prototypes are added to the LookUpResult. +/// Get the QualType instances of the return type and arguments for an OpenCL +/// builtin function signature. +/// \param Context (in) The Context instance. +/// \param OpenCLBuiltin (in) The signature currently handled. +/// \param GenTypeMaxCnt (out) Maximum number of types contained in a generic +/// type used as return type or as argument. +/// Only meaningful for generic types, otherwise equals 1. +/// \param RetTypes (out) List of the possible return types. +/// \param ArgTypes (out) List of the possible argument types. For each +/// argument, ArgTypes contains QualTypes for the Cartesian product +/// of (vector sizes) x (types) . +static void GetQualTypesForOpenCLBuiltin( + ASTContext &Context, const OpenCLBuiltinStruct &OpenCLBuiltin, + unsigned &GenTypeMaxCnt, SmallVector<QualType, 1> &RetTypes, + SmallVector<SmallVector<QualType, 1>, 5> &ArgTypes) { + // Get the QualType instances of the return types. + unsigned Sig = SignatureTable[OpenCLBuiltin.SigTableIndex]; + OCL2Qual(Context, TypeTable[Sig], RetTypes); + GenTypeMaxCnt = RetTypes.size(); + + // Get the QualType instances of the arguments. + // First type is the return type, skip it. + for (unsigned Index = 1; Index < OpenCLBuiltin.NumTypes; Index++) { + SmallVector<QualType, 1> Ty; + OCL2Qual(Context, + TypeTable[SignatureTable[OpenCLBuiltin.SigTableIndex + Index]], Ty); + GenTypeMaxCnt = (Ty.size() > GenTypeMaxCnt) ? Ty.size() : GenTypeMaxCnt; + ArgTypes.push_back(std::move(Ty)); + } +} + +/// Create a list of the candidate function overloads for an OpenCL builtin +/// function. +/// \param Context (in) The ASTContext instance. +/// \param GenTypeMaxCnt (in) Maximum number of types contained in a generic +/// type used as return type or as argument. +/// Only meaningful for generic types, otherwise equals 1. +/// \param FunctionList (out) List of FunctionTypes. +/// \param RetTypes (in) List of the possible return types. +/// \param ArgTypes (in) List of the possible types for the arguments. +static void GetOpenCLBuiltinFctOverloads( + ASTContext &Context, unsigned GenTypeMaxCnt, + std::vector<QualType> &FunctionList, SmallVector<QualType, 1> &RetTypes, + SmallVector<SmallVector<QualType, 1>, 5> &ArgTypes) { + FunctionProtoType::ExtProtoInfo PI; + PI.Variadic = false; + + // Create FunctionTypes for each (gen)type. + for (unsigned IGenType = 0; IGenType < GenTypeMaxCnt; IGenType++) { + SmallVector<QualType, 5> ArgList; + + for (unsigned A = 0; A < ArgTypes.size(); A++) { + // Builtins such as "max" have an "sgentype" argument that represents + // the corresponding scalar type of a gentype. The number of gentypes + // must be a multiple of the number of sgentypes. + assert(GenTypeMaxCnt % ArgTypes[A].size() == 0 && + "argument type count not compatible with gentype type count"); + unsigned Idx = IGenType % ArgTypes[A].size(); + ArgList.push_back(ArgTypes[A][Idx]); + } + + FunctionList.push_back(Context.getFunctionType( + RetTypes[(RetTypes.size() != 1) ? IGenType : 0], ArgList, PI)); + } +} + +/// 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. /// -/// \param S The Sema instance -/// \param LR The LookupResult instance -/// \param II The identifier being resolved -/// \param Index The list of prototypes starts at Index in OpenCLBuiltins[] -/// \param Len The list of prototypes has Len elements -static void InsertOCLBuiltinDeclarations(Sema &S, LookupResult &LR, - IdentifierInfo *II, unsigned Index, - unsigned Len) { - - for (unsigned i = 0; i < Len; ++i) { - const OpenCLBuiltinDecl &Decl = OpenCLBuiltins[Index - 1 + i]; +/// \param S (in) The Sema instance. +/// \param LR (inout) The LookupResult instance. +/// \param II (in) The identifier being resolved. +/// \param FctIndex (in) Starting index in the BuiltinTable. +/// \param Len (in) The signature list has Len elements. +static void InsertOCLBuiltinDeclarationsFromTable(Sema &S, LookupResult &LR, + IdentifierInfo *II, + const unsigned FctIndex, + const unsigned Len) { + // The builtin function declaration uses generic types (gentype). + bool HasGenType = false; + + // Maximum number of types contained in a generic type used as return type or + // as argument. Only meaningful for generic types, otherwise equals 1. + unsigned GenTypeMaxCnt; + + for (unsigned SignatureIndex = 0; SignatureIndex < Len; SignatureIndex++) { + const OpenCLBuiltinStruct &OpenCLBuiltin = + BuiltinTable[FctIndex + SignatureIndex]; ASTContext &Context = S.Context; - // Ignore this BIF if the version is incorrect. - if (Context.getLangOpts().OpenCLVersion < Decl.Version) + // Ignore this BIF if its version does not match the language options. + if (Context.getLangOpts().OpenCLVersion < OpenCLBuiltin.MinVersion) + continue; + if ((OpenCLBuiltin.MaxVersion != 0) && + (Context.getLangOpts().OpenCLVersion >= OpenCLBuiltin.MaxVersion)) continue; - FunctionProtoType::ExtProtoInfo PI; - PI.Variadic = false; - - // Defined in "OpenCLBuiltins.inc" - QualType RT = OCL2Qual(Context, OpenCLSignature[Decl.ArgTableIndex]); + SmallVector<QualType, 1> RetTypes; + SmallVector<SmallVector<QualType, 1>, 5> ArgTypes; - SmallVector<QualType, 5> ArgTypes; - for (unsigned I = 1; I < Decl.NumArgs; I++) { - QualType Ty = OCL2Qual(Context, OpenCLSignature[Decl.ArgTableIndex + I]); - ArgTypes.push_back(Ty); + // Obtain QualType lists for the function signature. + GetQualTypesForOpenCLBuiltin(Context, OpenCLBuiltin, GenTypeMaxCnt, + RetTypes, ArgTypes); + if (GenTypeMaxCnt > 1) { + HasGenType = true; } - QualType R = Context.getFunctionType(RT, ArgTypes, PI); - SourceLocation Loc = LR.getNameLoc(); + // Create function overload for each type combination. + std::vector<QualType> FunctionList; + GetOpenCLBuiltinFctOverloads(Context, GenTypeMaxCnt, FunctionList, RetTypes, + ArgTypes); - // TODO: This part is taken from Sema::LazilyCreateBuiltin, - // maybe refactor it. + SourceLocation Loc = LR.getNameLoc(); DeclContext *Parent = Context.getTranslationUnitDecl(); - FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, R, - /*TInfo=*/nullptr, SC_Extern, - false, R->isFunctionProtoType()); - New->setImplicit(); - - // Create Decl objects for each parameter, adding them to the - // FunctionDecl. - if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) { - SmallVector<ParmVarDecl *, 16> Params; - for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) { - ParmVarDecl *Parm = - ParmVarDecl::Create(Context, New, SourceLocation(), - SourceLocation(), nullptr, FT->getParamType(i), - /*TInfo=*/nullptr, SC_None, nullptr); - Parm->setScopeInfo(0, i); - Params.push_back(Parm); + FunctionDecl *NewOpenCLBuiltin; + + for (unsigned Index = 0; Index < GenTypeMaxCnt; Index++) { + NewOpenCLBuiltin = FunctionDecl::Create( + Context, Parent, Loc, Loc, II, FunctionList[Index], + /*TInfo=*/nullptr, SC_Extern, false, + FunctionList[Index]->isFunctionProtoType()); + NewOpenCLBuiltin->setImplicit(); + + // Create Decl objects for each parameter, adding them to the + // FunctionDecl. + if (const FunctionProtoType *FP = + dyn_cast<FunctionProtoType>(FunctionList[Index])) { + SmallVector<ParmVarDecl *, 16> ParmList; + for (unsigned IParm = 0, e = FP->getNumParams(); IParm != e; ++IParm) { + ParmVarDecl *Parm = ParmVarDecl::Create( + Context, NewOpenCLBuiltin, SourceLocation(), SourceLocation(), + nullptr, FP->getParamType(IParm), + /*TInfo=*/nullptr, SC_None, nullptr); + Parm->setScopeInfo(0, IParm); + ParmList.push_back(Parm); + } + NewOpenCLBuiltin->setParams(ParmList); } - New->setParams(Params); + if (!S.getLangOpts().OpenCLCPlusPlus) { + NewOpenCLBuiltin->addAttr(OverloadableAttr::CreateImplicit(Context)); + } + LR.addDecl(NewOpenCLBuiltin); } - - New->addAttr(OverloadableAttr::CreateImplicit(Context)); - - if (strlen(Decl.Extension)) - S.setOpenCLExtensionForDecl(New, Decl.Extension); - - LR.addDecl(New); } // If we added overloads, need to resolve the lookup result. - if (Len > 1) + if (Len > 1 || HasGenType) LR.resolveKind(); } /// Lookup a builtin function, when name lookup would otherwise /// fail. -static bool LookupBuiltin(Sema &S, LookupResult &R) { +bool Sema::LookupBuiltin(LookupResult &R) { Sema::LookupNameKind NameKind = R.getLookupKind(); // If we didn't find a use of this identifier, and if the identifier @@ -758,21 +836,22 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) { NameKind == Sema::LookupRedeclarationWithLinkage) { IdentifierInfo *II = R.getLookupName().getAsIdentifierInfo(); if (II) { - if (S.getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName) { - if (II == S.getASTContext().getMakeIntegerSeqName()) { - R.addDecl(S.getASTContext().getMakeIntegerSeqDecl()); + if (getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName) { + if (II == getASTContext().getMakeIntegerSeqName()) { + R.addDecl(getASTContext().getMakeIntegerSeqDecl()); return true; - } else if (II == S.getASTContext().getTypePackElementName()) { - R.addDecl(S.getASTContext().getTypePackElementDecl()); + } else if (II == getASTContext().getTypePackElementName()) { + R.addDecl(getASTContext().getTypePackElementDecl()); return true; } } // Check if this is an OpenCL Builtin, and if so, insert its overloads. - if (S.getLangOpts().OpenCL && S.getLangOpts().DeclareOpenCLBuiltins) { + if (getLangOpts().OpenCL && getLangOpts().DeclareOpenCLBuiltins) { auto Index = isOpenCLBuiltin(II->getName()); if (Index.first) { - InsertOCLBuiltinDeclarations(S, R, II, Index.first, Index.second); + InsertOCLBuiltinDeclarationsFromTable(*this, R, II, Index.first - 1, + Index.second); return true; } } @@ -781,14 +860,14 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) { if (unsigned BuiltinID = II->getBuiltinID()) { // In C++ and OpenCL (spec v1.2 s6.9.f), we don't have any predefined // library functions like 'malloc'. Instead, we'll just error. - if ((S.getLangOpts().CPlusPlus || S.getLangOpts().OpenCL) && - S.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) + if ((getLangOpts().CPlusPlus || getLangOpts().OpenCL) && + Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) return false; - if (NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II, - BuiltinID, S.TUScope, - R.isForRedeclaration(), - R.getNameLoc())) { + if (NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, + BuiltinID, TUScope, + R.isForRedeclaration(), + R.getNameLoc())) { R.addDecl(D); return true; } @@ -934,7 +1013,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { } } - if (!Found && DC->isTranslationUnit() && LookupBuiltin(S, R)) + if (!Found && DC->isTranslationUnit() && S.LookupBuiltin(R)) return true; if (R.getLookupName().getNameKind() @@ -1932,7 +2011,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { // If we didn't find a use of this identifier, and if the identifier // corresponds to a compiler builtin, create the decl object for the builtin // now, injecting it into translation unit scope, and return it. - if (AllowBuiltinCreation && LookupBuiltin(*this, R)) + if (AllowBuiltinCreation && LookupBuiltin(R)) return true; // If we didn't find a use of this identifier, the ExternalSource @@ -2051,7 +2130,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, /// Callback that looks for any member of a class with the given name. static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, DeclarationName Name) { - RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); + RecordDecl *BaseRecord = Specifier->getType()->castAs<RecordType>()->getDecl(); Path.Decls = BaseRecord->lookup(Name); return !Path.Decls.empty(); @@ -2750,7 +2829,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { #define NON_CANONICAL_TYPE(Class, Base) case Type::Class: #define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class: #define ABSTRACT_TYPE(Class, Base) -#include "clang/AST/TypeNodes.def" +#include "clang/AST/TypeNodes.inc" // T is canonical. We can also ignore dependent types because // we don't need to do ADL at the definition point, but if we // wanted to implement template export (or if we find some other @@ -3016,8 +3095,11 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, SpecialMemberCache.InsertNode(Result, InsertPoint); if (SM == CXXDestructor) { - if (RD->needsImplicitDestructor()) - DeclareImplicitDestructor(RD); + if (RD->needsImplicitDestructor()) { + runWithSufficientStackSpace(RD->getLocation(), [&] { + DeclareImplicitDestructor(RD); + }); + } CXXDestructorDecl *DD = RD->getDestructor(); assert(DD && "record without a destructor"); Result->setMethod(DD); @@ -3040,21 +3122,36 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, if (SM == CXXDefaultConstructor) { Name = Context.DeclarationNames.getCXXConstructorName(CanTy); NumArgs = 0; - if (RD->needsImplicitDefaultConstructor()) - DeclareImplicitDefaultConstructor(RD); + if (RD->needsImplicitDefaultConstructor()) { + runWithSufficientStackSpace(RD->getLocation(), [&] { + DeclareImplicitDefaultConstructor(RD); + }); + } } else { if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) { Name = Context.DeclarationNames.getCXXConstructorName(CanTy); - if (RD->needsImplicitCopyConstructor()) - DeclareImplicitCopyConstructor(RD); - if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveConstructor()) - DeclareImplicitMoveConstructor(RD); + if (RD->needsImplicitCopyConstructor()) { + runWithSufficientStackSpace(RD->getLocation(), [&] { + DeclareImplicitCopyConstructor(RD); + }); + } + if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveConstructor()) { + runWithSufficientStackSpace(RD->getLocation(), [&] { + DeclareImplicitMoveConstructor(RD); + }); + } } else { Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); - if (RD->needsImplicitCopyAssignment()) - DeclareImplicitCopyAssignment(RD); - if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveAssignment()) - DeclareImplicitMoveAssignment(RD); + if (RD->needsImplicitCopyAssignment()) { + runWithSufficientStackSpace(RD->getLocation(), [&] { + DeclareImplicitCopyAssignment(RD); + }); + } + if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveAssignment()) { + runWithSufficientStackSpace(RD->getLocation(), [&] { + DeclareImplicitMoveAssignment(RD); + }); + } } if (ConstArg) @@ -3211,12 +3308,14 @@ CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class, DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { // If the implicit constructors have not yet been declared, do so now. if (CanDeclareSpecialMemberFunction(Class)) { - if (Class->needsImplicitDefaultConstructor()) - DeclareImplicitDefaultConstructor(Class); - if (Class->needsImplicitCopyConstructor()) - DeclareImplicitCopyConstructor(Class); - if (getLangOpts().CPlusPlus11 && Class->needsImplicitMoveConstructor()) - DeclareImplicitMoveConstructor(Class); + runWithSufficientStackSpace(Class->getLocation(), [&] { + if (Class->needsImplicitDefaultConstructor()) + DeclareImplicitDefaultConstructor(Class); + if (Class->needsImplicitCopyConstructor()) + DeclareImplicitCopyConstructor(Class); + if (getLangOpts().CPlusPlus11 && Class->needsImplicitMoveConstructor()) + DeclareImplicitMoveConstructor(Class); + }); } CanQualType T = Context.getCanonicalType(Context.getTypeDeclType(Class)); @@ -3609,328 +3708,347 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { return nullptr; } -static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, - bool QualifiedNameLookup, - bool InBaseClass, - VisibleDeclConsumer &Consumer, - VisibleDeclsRecord &Visited, - bool IncludeDependentBases, - bool LoadExternal) { - if (!Ctx) - return; - - // Make sure we don't visit the same context twice. - if (Visited.visitedContext(Ctx->getPrimaryContext())) - return; - - Consumer.EnteredContext(Ctx); - - // Outside C++, lookup results for the TU live on identifiers. - if (isa<TranslationUnitDecl>(Ctx) && - !Result.getSema().getLangOpts().CPlusPlus) { - auto &S = Result.getSema(); - auto &Idents = S.Context.Idents; - - // Ensure all external identifiers are in the identifier table. - if (LoadExternal) - if (IdentifierInfoLookup *External = Idents.getExternalIdentifierLookup()) { - std::unique_ptr<IdentifierIterator> Iter(External->getIdentifiers()); - for (StringRef Name = Iter->Next(); !Name.empty(); Name = Iter->Next()) - Idents.get(Name); - } +namespace { +class LookupVisibleHelper { +public: + LookupVisibleHelper(VisibleDeclConsumer &Consumer, bool IncludeDependentBases, + bool LoadExternal) + : Consumer(Consumer), IncludeDependentBases(IncludeDependentBases), + LoadExternal(LoadExternal) {} + + void lookupVisibleDecls(Sema &SemaRef, Scope *S, Sema::LookupNameKind Kind, + bool IncludeGlobalScope) { + // Determine the set of using directives available during + // unqualified name lookup. + Scope *Initial = S; + UnqualUsingDirectiveSet UDirs(SemaRef); + if (SemaRef.getLangOpts().CPlusPlus) { + // Find the first namespace or translation-unit scope. + while (S && !isNamespaceOrTranslationUnitScope(S)) + S = S->getParent(); - // Walk all lookup results in the TU for each identifier. - for (const auto &Ident : Idents) { - for (auto I = S.IdResolver.begin(Ident.getValue()), - E = S.IdResolver.end(); - I != E; ++I) { - if (S.IdResolver.isDeclInScope(*I, Ctx)) { - if (NamedDecl *ND = Result.getAcceptableDecl(*I)) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); - Visited.add(ND); - } - } - } + UDirs.visitScopeChain(Initial, S); } + UDirs.done(); - return; + // Look for visible declarations. + LookupResult Result(SemaRef, DeclarationName(), SourceLocation(), Kind); + Result.setAllowHidden(Consumer.includeHiddenDecls()); + if (!IncludeGlobalScope) + Visited.visitedContext(SemaRef.getASTContext().getTranslationUnitDecl()); + ShadowContextRAII Shadow(Visited); + lookupInScope(Initial, Result, UDirs); } - if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) - Result.getSema().ForceDeclarationOfImplicitMembers(Class); + void lookupVisibleDecls(Sema &SemaRef, DeclContext *Ctx, + Sema::LookupNameKind Kind, bool IncludeGlobalScope) { + LookupResult Result(SemaRef, DeclarationName(), SourceLocation(), Kind); + Result.setAllowHidden(Consumer.includeHiddenDecls()); + if (!IncludeGlobalScope) + Visited.visitedContext(SemaRef.getASTContext().getTranslationUnitDecl()); - // We sometimes skip loading namespace-level results (they tend to be huge). - bool Load = LoadExternal || - !(isa<TranslationUnitDecl>(Ctx) || isa<NamespaceDecl>(Ctx)); - // Enumerate all of the results in this context. - for (DeclContextLookupResult R : - Load ? Ctx->lookups() - : Ctx->noload_lookups(/*PreserveInternalState=*/false)) { - for (auto *D : R) { - if (auto *ND = Result.getAcceptableDecl(D)) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); - Visited.add(ND); - } - } - } - - // Traverse using directives for qualified name lookup. - if (QualifiedNameLookup) { ShadowContextRAII Shadow(Visited); - for (auto I : Ctx->using_directives()) { - if (!Result.getSema().isVisible(I)) - continue; - LookupVisibleDecls(I->getNominatedNamespace(), Result, - QualifiedNameLookup, InBaseClass, Consumer, Visited, - IncludeDependentBases, LoadExternal); - } + lookupInDeclContext(Ctx, Result, /*QualifiedNameLookup=*/true, + /*InBaseClass=*/false); } - // Traverse the contexts of inherited C++ classes. - if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) { - if (!Record->hasDefinition()) +private: + void lookupInDeclContext(DeclContext *Ctx, LookupResult &Result, + bool QualifiedNameLookup, bool InBaseClass) { + if (!Ctx) return; - for (const auto &B : Record->bases()) { - QualType BaseType = B.getType(); + // Make sure we don't visit the same context twice. + if (Visited.visitedContext(Ctx->getPrimaryContext())) + return; - RecordDecl *RD; - if (BaseType->isDependentType()) { - if (!IncludeDependentBases) { - // Don't look into dependent bases, because name lookup can't look - // there anyway. - continue; + Consumer.EnteredContext(Ctx); + + // Outside C++, lookup results for the TU live on identifiers. + if (isa<TranslationUnitDecl>(Ctx) && + !Result.getSema().getLangOpts().CPlusPlus) { + auto &S = Result.getSema(); + auto &Idents = S.Context.Idents; + + // Ensure all external identifiers are in the identifier table. + if (LoadExternal) + if (IdentifierInfoLookup *External = + Idents.getExternalIdentifierLookup()) { + std::unique_ptr<IdentifierIterator> Iter(External->getIdentifiers()); + for (StringRef Name = Iter->Next(); !Name.empty(); + Name = Iter->Next()) + Idents.get(Name); + } + + // Walk all lookup results in the TU for each identifier. + for (const auto &Ident : Idents) { + for (auto I = S.IdResolver.begin(Ident.getValue()), + E = S.IdResolver.end(); + I != E; ++I) { + if (S.IdResolver.isDeclInScope(*I, Ctx)) { + if (NamedDecl *ND = Result.getAcceptableDecl(*I)) { + Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); + Visited.add(ND); + } + } } - const auto *TST = BaseType->getAs<TemplateSpecializationType>(); - if (!TST) - continue; - TemplateName TN = TST->getTemplateName(); - const auto *TD = - dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl()); - if (!TD) - continue; - RD = TD->getTemplatedDecl(); - } else { - const auto *Record = BaseType->getAs<RecordType>(); - if (!Record) - continue; - RD = Record->getDecl(); } - // FIXME: It would be nice to be able to determine whether referencing - // a particular member would be ambiguous. For example, given - // - // struct A { int member; }; - // struct B { int member; }; - // struct C : A, B { }; - // - // void f(C *c) { c->### } - // - // accessing 'member' would result in an ambiguity. However, we - // could be smart enough to qualify the member with the base - // class, e.g., - // - // c->B::member - // - // or - // - // c->A::member - - // Find results in this base class (and its bases). - ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(RD, Result, QualifiedNameLookup, /*InBaseClass=*/true, - Consumer, Visited, IncludeDependentBases, - LoadExternal); + return; } - } - // Traverse the contexts of Objective-C classes. - if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) { - // Traverse categories. - for (auto *Cat : IFace->visible_categories()) { - ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(Cat, Result, QualifiedNameLookup, false, Consumer, - Visited, IncludeDependentBases, LoadExternal); + if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) + Result.getSema().ForceDeclarationOfImplicitMembers(Class); + + // We sometimes skip loading namespace-level results (they tend to be huge). + bool Load = LoadExternal || + !(isa<TranslationUnitDecl>(Ctx) || isa<NamespaceDecl>(Ctx)); + // Enumerate all of the results in this context. + for (DeclContextLookupResult R : + Load ? Ctx->lookups() + : Ctx->noload_lookups(/*PreserveInternalState=*/false)) { + for (auto *D : R) { + if (auto *ND = Result.getAcceptableDecl(D)) { + Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); + Visited.add(ND); + } + } } - // Traverse protocols. - for (auto *I : IFace->all_referenced_protocols()) { + // Traverse using directives for qualified name lookup. + if (QualifiedNameLookup) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, - Visited, IncludeDependentBases, LoadExternal); + for (auto I : Ctx->using_directives()) { + if (!Result.getSema().isVisible(I)) + continue; + lookupInDeclContext(I->getNominatedNamespace(), Result, + QualifiedNameLookup, InBaseClass); + } } - // Traverse the superclass. - if (IFace->getSuperClass()) { - ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup, - true, Consumer, Visited, IncludeDependentBases, - LoadExternal); - } + // Traverse the contexts of inherited C++ classes. + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) { + if (!Record->hasDefinition()) + return; - // If there is an implementation, traverse it. We do this to find - // synthesized ivars. - if (IFace->getImplementation()) { - ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(IFace->getImplementation(), Result, - QualifiedNameLookup, InBaseClass, Consumer, Visited, - IncludeDependentBases, LoadExternal); - } - } else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) { - for (auto *I : Protocol->protocols()) { - ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, - Visited, IncludeDependentBases, LoadExternal); - } - } else if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Ctx)) { - for (auto *I : Category->protocols()) { - ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, - Visited, IncludeDependentBases, LoadExternal); + for (const auto &B : Record->bases()) { + QualType BaseType = B.getType(); + + RecordDecl *RD; + if (BaseType->isDependentType()) { + if (!IncludeDependentBases) { + // Don't look into dependent bases, because name lookup can't look + // there anyway. + continue; + } + const auto *TST = BaseType->getAs<TemplateSpecializationType>(); + if (!TST) + continue; + TemplateName TN = TST->getTemplateName(); + const auto *TD = + dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl()); + if (!TD) + continue; + RD = TD->getTemplatedDecl(); + } else { + const auto *Record = BaseType->getAs<RecordType>(); + if (!Record) + continue; + RD = Record->getDecl(); + } + + // FIXME: It would be nice to be able to determine whether referencing + // a particular member would be ambiguous. For example, given + // + // struct A { int member; }; + // struct B { int member; }; + // struct C : A, B { }; + // + // void f(C *c) { c->### } + // + // accessing 'member' would result in an ambiguity. However, we + // could be smart enough to qualify the member with the base + // class, e.g., + // + // c->B::member + // + // or + // + // c->A::member + + // Find results in this base class (and its bases). + ShadowContextRAII Shadow(Visited); + lookupInDeclContext(RD, Result, QualifiedNameLookup, + /*InBaseClass=*/true); + } } - // If there is an implementation, traverse it. - if (Category->getImplementation()) { - ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(Category->getImplementation(), Result, - QualifiedNameLookup, true, Consumer, Visited, - IncludeDependentBases, LoadExternal); + // Traverse the contexts of Objective-C classes. + if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) { + // Traverse categories. + for (auto *Cat : IFace->visible_categories()) { + ShadowContextRAII Shadow(Visited); + lookupInDeclContext(Cat, Result, QualifiedNameLookup, + /*InBaseClass=*/false); + } + + // Traverse protocols. + for (auto *I : IFace->all_referenced_protocols()) { + ShadowContextRAII Shadow(Visited); + lookupInDeclContext(I, Result, QualifiedNameLookup, + /*InBaseClass=*/false); + } + + // Traverse the superclass. + if (IFace->getSuperClass()) { + ShadowContextRAII Shadow(Visited); + lookupInDeclContext(IFace->getSuperClass(), Result, QualifiedNameLookup, + /*InBaseClass=*/true); + } + + // If there is an implementation, traverse it. We do this to find + // synthesized ivars. + if (IFace->getImplementation()) { + ShadowContextRAII Shadow(Visited); + lookupInDeclContext(IFace->getImplementation(), Result, + QualifiedNameLookup, InBaseClass); + } + } else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) { + for (auto *I : Protocol->protocols()) { + ShadowContextRAII Shadow(Visited); + lookupInDeclContext(I, Result, QualifiedNameLookup, + /*InBaseClass=*/false); + } + } else if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Ctx)) { + for (auto *I : Category->protocols()) { + ShadowContextRAII Shadow(Visited); + lookupInDeclContext(I, Result, QualifiedNameLookup, + /*InBaseClass=*/false); + } + + // If there is an implementation, traverse it. + if (Category->getImplementation()) { + ShadowContextRAII Shadow(Visited); + lookupInDeclContext(Category->getImplementation(), Result, + QualifiedNameLookup, /*InBaseClass=*/true); + } } } -} -static void LookupVisibleDecls(Scope *S, LookupResult &Result, - UnqualUsingDirectiveSet &UDirs, - VisibleDeclConsumer &Consumer, - VisibleDeclsRecord &Visited, - bool LoadExternal) { - if (!S) - return; + void lookupInScope(Scope *S, LookupResult &Result, + UnqualUsingDirectiveSet &UDirs) { + // No clients run in this mode and it's not supported. Please add tests and + // remove the assertion if you start relying on it. + assert(!IncludeDependentBases && "Unsupported flag for lookupInScope"); - if (!S->getEntity() || - (!S->getParent() && - !Visited.alreadyVisitedContext(S->getEntity())) || - (S->getEntity())->isFunctionOrMethod()) { - FindLocalExternScope FindLocals(Result); - // Walk through the declarations in this Scope. The consumer might add new - // decls to the scope as part of deserialization, so make a copy first. - SmallVector<Decl *, 8> ScopeDecls(S->decls().begin(), S->decls().end()); - for (Decl *D : ScopeDecls) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) - if ((ND = Result.getAcceptableDecl(ND))) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND), nullptr, false); - Visited.add(ND); - } + if (!S) + return; + + if (!S->getEntity() || + (!S->getParent() && !Visited.alreadyVisitedContext(S->getEntity())) || + (S->getEntity())->isFunctionOrMethod()) { + FindLocalExternScope FindLocals(Result); + // Walk through the declarations in this Scope. The consumer might add new + // decls to the scope as part of deserialization, so make a copy first. + SmallVector<Decl *, 8> ScopeDecls(S->decls().begin(), S->decls().end()); + for (Decl *D : ScopeDecls) { + if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) + if ((ND = Result.getAcceptableDecl(ND))) { + Consumer.FoundDecl(ND, Visited.checkHidden(ND), nullptr, false); + Visited.add(ND); + } + } } - } - // FIXME: C++ [temp.local]p8 - DeclContext *Entity = nullptr; - if (S->getEntity()) { - // Look into this scope's declaration context, along with any of its - // parent lookup contexts (e.g., enclosing classes), up to the point - // where we hit the context stored in the next outer scope. - Entity = S->getEntity(); - DeclContext *OuterCtx = findOuterContext(S).first; // FIXME - - for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx); - Ctx = Ctx->getLookupParent()) { - if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) { - if (Method->isInstanceMethod()) { - // For instance methods, look for ivars in the method's interface. - LookupResult IvarResult(Result.getSema(), Result.getLookupName(), - Result.getNameLoc(), Sema::LookupMemberName); - if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) { - LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited, - /*IncludeDependentBases=*/false, LoadExternal); + // FIXME: C++ [temp.local]p8 + DeclContext *Entity = nullptr; + if (S->getEntity()) { + // Look into this scope's declaration context, along with any of its + // parent lookup contexts (e.g., enclosing classes), up to the point + // where we hit the context stored in the next outer scope. + Entity = S->getEntity(); + DeclContext *OuterCtx = findOuterContext(S).first; // FIXME + + for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx); + Ctx = Ctx->getLookupParent()) { + if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) { + if (Method->isInstanceMethod()) { + // For instance methods, look for ivars in the method's interface. + LookupResult IvarResult(Result.getSema(), Result.getLookupName(), + Result.getNameLoc(), + Sema::LookupMemberName); + if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) { + lookupInDeclContext(IFace, IvarResult, + /*QualifiedNameLookup=*/false, + /*InBaseClass=*/false); + } } + + // We've already performed all of the name lookup that we need + // to for Objective-C methods; the next context will be the + // outer scope. + break; } - // We've already performed all of the name lookup that we need - // to for Objective-C methods; the next context will be the - // outer scope. - break; - } + if (Ctx->isFunctionOrMethod()) + continue; - if (Ctx->isFunctionOrMethod()) - continue; + lookupInDeclContext(Ctx, Result, /*QualifiedNameLookup=*/false, + /*InBaseClass=*/false); + } + } else if (!S->getParent()) { + // Look into the translation unit scope. We walk through the translation + // unit's declaration context, because the Scope itself won't have all of + // the declarations if we loaded a precompiled header. + // FIXME: We would like the translation unit's Scope object to point to + // the translation unit, so we don't need this special "if" branch. + // However, doing so would force the normal C++ name-lookup code to look + // into the translation unit decl when the IdentifierInfo chains would + // suffice. Once we fix that problem (which is part of a more general + // "don't look in DeclContexts unless we have to" optimization), we can + // eliminate this. + Entity = Result.getSema().Context.getTranslationUnitDecl(); + lookupInDeclContext(Entity, Result, /*QualifiedNameLookup=*/false, + /*InBaseClass=*/false); + } - LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited, - /*IncludeDependentBases=*/false, LoadExternal); + if (Entity) { + // Lookup visible declarations in any namespaces found by using + // directives. + for (const UnqualUsingEntry &UUE : UDirs.getNamespacesFor(Entity)) + lookupInDeclContext( + const_cast<DeclContext *>(UUE.getNominatedNamespace()), Result, + /*QualifiedNameLookup=*/false, + /*InBaseClass=*/false); } - } else if (!S->getParent()) { - // Look into the translation unit scope. We walk through the translation - // unit's declaration context, because the Scope itself won't have all of - // the declarations if we loaded a precompiled header. - // FIXME: We would like the translation unit's Scope object to point to the - // translation unit, so we don't need this special "if" branch. However, - // doing so would force the normal C++ name-lookup code to look into the - // translation unit decl when the IdentifierInfo chains would suffice. - // Once we fix that problem (which is part of a more general "don't look - // in DeclContexts unless we have to" optimization), we can eliminate this. - Entity = Result.getSema().Context.getTranslationUnitDecl(); - LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited, - /*IncludeDependentBases=*/false, LoadExternal); - } - if (Entity) { - // Lookup visible declarations in any namespaces found by using - // directives. - for (const UnqualUsingEntry &UUE : UDirs.getNamespacesFor(Entity)) - LookupVisibleDecls(const_cast<DeclContext *>(UUE.getNominatedNamespace()), - Result, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited, - /*IncludeDependentBases=*/false, LoadExternal); + // Lookup names in the parent scope. + ShadowContextRAII Shadow(Visited); + lookupInScope(S->getParent(), Result, UDirs); } - // Lookup names in the parent scope. - ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(S->getParent(), Result, UDirs, Consumer, Visited, - LoadExternal); -} +private: + VisibleDeclsRecord Visited; + VisibleDeclConsumer &Consumer; + bool IncludeDependentBases; + bool LoadExternal; +}; +} // namespace void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope, bool LoadExternal) { - // Determine the set of using directives available during - // unqualified name lookup. - Scope *Initial = S; - UnqualUsingDirectiveSet UDirs(*this); - if (getLangOpts().CPlusPlus) { - // Find the first namespace or translation-unit scope. - while (S && !isNamespaceOrTranslationUnitScope(S)) - S = S->getParent(); - - UDirs.visitScopeChain(Initial, S); - } - UDirs.done(); - - // Look for visible declarations. - LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); - Result.setAllowHidden(Consumer.includeHiddenDecls()); - VisibleDeclsRecord Visited; - if (!IncludeGlobalScope) - Visited.visitedContext(Context.getTranslationUnitDecl()); - ShadowContextRAII Shadow(Visited); - ::LookupVisibleDecls(Initial, Result, UDirs, Consumer, Visited, LoadExternal); + LookupVisibleHelper H(Consumer, /*IncludeDependentBases=*/false, + LoadExternal); + H.lookupVisibleDecls(*this, S, Kind, IncludeGlobalScope); } void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope, bool IncludeDependentBases, bool LoadExternal) { - LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); - Result.setAllowHidden(Consumer.includeHiddenDecls()); - VisibleDeclsRecord Visited; - if (!IncludeGlobalScope) - Visited.visitedContext(Context.getTranslationUnitDecl()); - ShadowContextRAII Shadow(Visited); - ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, - /*InBaseClass=*/false, Consumer, Visited, - IncludeDependentBases, LoadExternal); + LookupVisibleHelper H(Consumer, IncludeDependentBases, LoadExternal); + H.lookupVisibleDecls(*this, Ctx, Kind, IncludeGlobalScope); } /// LookupOrCreateLabel - Do a name lookup of a label with the specified name. @@ -4745,7 +4863,7 @@ std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer( // occurs). Note that CorrectionCandidateCallback is polymorphic and // initially stack-allocated. std::unique_ptr<CorrectionCandidateCallback> ClonedCCC = CCC.clone(); - auto Consumer = llvm::make_unique<TypoCorrectionConsumer>( + auto Consumer = std::make_unique<TypoCorrectionConsumer>( *this, TypoName, LookupKind, S, SS, std::move(ClonedCCC), MemberContext, EnteringContext); @@ -5164,8 +5282,11 @@ static NamedDecl *getDefinitionToImport(NamedDecl *D) { return FD->getDefinition(); if (TagDecl *TD = dyn_cast<TagDecl>(D)) return TD->getDefinition(); + // The first definition for this ObjCInterfaceDecl might be in the TU + // and not associated with any module. Use the one we know to be complete + // and have just seen in a module. if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) - return ID->getDefinition(); + return ID; if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) return PD->getDefinition(); if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) @@ -5361,6 +5482,8 @@ TypoExpr *Sema::createDelayedTypo(std::unique_ptr<TypoCorrectionConsumer> TCC, State.Consumer = std::move(TCC); State.DiagHandler = std::move(TDG); State.RecoveryHandler = std::move(TRC); + if (TE) + TypoExprs.push_back(TE); return TE; } diff --git a/lib/Sema/SemaModule.cpp b/lib/Sema/SemaModule.cpp index 10de0ca91221..1fca351bfb09 100644 --- a/lib/Sema/SemaModule.cpp +++ b/lib/Sema/SemaModule.cpp @@ -31,6 +31,8 @@ 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/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index e5c014501431..ac810745d2f5 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -735,7 +735,7 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc, return; // If the ivar is private, and it's implicitly __unsafe_unretained - // becaues of its type, then pretend it was actually implicitly + // because of its type, then pretend it was actually implicitly // __strong. This is only sound because we're processing the // property implementation before parsing any method bodies. if (ivarLifetime == Qualifiers::OCL_ExplicitNone && @@ -2419,9 +2419,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { ObjCReturnsInnerPointerAttr::CreateImplicit(Context, Loc)); if (const SectionAttr *SA = property->getAttr<SectionAttr>()) - GetterMethod->addAttr( - SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section, - SA->getName(), Loc)); + GetterMethod->addAttr(SectionAttr::CreateImplicit( + Context, SA->getName(), Loc, AttributeCommonInfo::AS_GNU, + SectionAttr::GNU_section)); if (getLangOpts().ObjCAutoRefCount) CheckARCMethodDecl(GetterMethod); @@ -2485,9 +2485,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { CD->addDecl(SetterMethod); if (const SectionAttr *SA = property->getAttr<SectionAttr>()) - SetterMethod->addAttr( - SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section, - SA->getName(), Loc)); + SetterMethod->addAttr(SectionAttr::CreateImplicit( + Context, SA->getName(), Loc, AttributeCommonInfo::AS_GNU, + SectionAttr::GNU_section)); // It's possible for the user to have set a very odd custom // setter selector that causes it to have a method family. if (getLangOpts().ObjCAutoRefCount) diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index bd68011c18b2..c7e0d2aee036 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -139,6 +139,7 @@ private: /// clause, false otherwise. llvm::Optional<std::pair<const Expr *, OMPOrderedClause *>> OrderedRegion; unsigned AssociatedLoops = 1; + bool HasMutipleLoops = false; const Decl *PossiblyLoopCounter = nullptr; bool NowaitRegion = false; bool CancelRegion = false; @@ -169,7 +170,7 @@ private: OpenMPClauseKind ClauseKindMode = OMPC_unknown; Sema &SemaRef; bool ForceCapturing = false; - /// true if all the vaiables in the target executable directives must be + /// true if all the variables in the target executable directives must be /// captured by reference. bool ForceCaptureByReferenceInTargetExecutable = false; CriticalsWithHintsTy Criticals; @@ -521,6 +522,13 @@ public: assert(!isStackEmpty() && "No directive at specified level."); return getStackElemAtLevel(Level).Directive; } + /// Returns the capture region at the specified level. + OpenMPDirectiveKind getCaptureRegion(unsigned Level, + unsigned OpenMPCaptureLevel) const { + SmallVector<OpenMPDirectiveKind, 4> CaptureRegions; + getOpenMPCaptureRegions(CaptureRegions, getDirective(Level)); + return CaptureRegions[OpenMPCaptureLevel]; + } /// Returns parent directive. OpenMPDirectiveKind getParentDirective() const { const SharingMapTy *Parent = getSecondOnStackOrNull(); @@ -678,12 +686,19 @@ public: /// Set collapse value for the region. void setAssociatedLoops(unsigned Val) { getTopOfStack().AssociatedLoops = Val; + if (Val > 1) + getTopOfStack().HasMutipleLoops = true; } /// Return collapse value for region. unsigned getAssociatedLoops() const { const SharingMapTy *Top = getTopOfStackOrNull(); return Top ? Top->AssociatedLoops : 0; } + /// Returns true if the construct is associated with multiple loops. + bool hasMutipleLoops() const { + const SharingMapTy *Top = getTopOfStackOrNull(); + return Top ? Top->HasMutipleLoops : false; + } /// Marks current target region as one with closely nested teams /// region. @@ -951,7 +966,8 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter, // In a parallel construct, if no default clause is present, these // variables are shared. DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; - if (isOpenMPParallelDirective(DVar.DKind) || + if ((isOpenMPParallelDirective(DVar.DKind) && + !isOpenMPTaskLoopDirective(DVar.DKind)) || isOpenMPTeamsDirective(DVar.DKind)) { DVar.CKind = OMPC_shared; return DVar; @@ -1332,7 +1348,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, } const_iterator End = end(); if (!SemaRef.isOpenMPCapturedByRef( - D, std::distance(ParentIterTarget, End))) { + D, std::distance(ParentIterTarget, End), + /*OpenMPCaptureLevel=*/0)) { DVar.RefExpr = buildDeclRefExpr(SemaRef, VD, D->getType().getNonReferenceType(), IterTarget->ConstructLoc); @@ -1540,49 +1557,150 @@ static bool isOpenMPDeviceDelayedContext(Sema &S) { !S.isInOpenMPDeclareTargetContext(); } -/// Do we know that we will eventually codegen the given function? -static bool isKnownEmitted(Sema &S, FunctionDecl *FD) { - assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsDevice && - "Expected OpenMP device compilation."); - // Templates are emitted when they're instantiated. - if (FD->isDependentContext()) - return false; - - if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration( - FD->getCanonicalDecl())) - return true; - - // Otherwise, the function is known-emitted if it's in our set of - // known-emitted functions. - return S.DeviceKnownEmittedFns.count(FD) > 0; -} +namespace { +/// Status of the function emission on the host/device. +enum class FunctionEmissionStatus { + Emitted, + Discarded, + Unknown, +}; +} // anonymous namespace Sema::DeviceDiagBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc, unsigned DiagID) { assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice && "Expected OpenMP device compilation."); - return DeviceDiagBuilder((isOpenMPDeviceDelayedContext(*this) && - !isKnownEmitted(*this, getCurFunctionDecl())) - ? DeviceDiagBuilder::K_Deferred - : DeviceDiagBuilder::K_Immediate, - Loc, DiagID, getCurFunctionDecl(), *this); + FunctionEmissionStatus FES = getEmissionStatus(getCurFunctionDecl()); + DeviceDiagBuilder::Kind Kind = DeviceDiagBuilder::K_Nop; + switch (FES) { + case FunctionEmissionStatus::Emitted: + Kind = DeviceDiagBuilder::K_Immediate; + break; + case FunctionEmissionStatus::Unknown: + Kind = isOpenMPDeviceDelayedContext(*this) ? DeviceDiagBuilder::K_Deferred + : DeviceDiagBuilder::K_Immediate; + break; + case FunctionEmissionStatus::TemplateDiscarded: + case FunctionEmissionStatus::OMPDiscarded: + Kind = DeviceDiagBuilder::K_Nop; + break; + case FunctionEmissionStatus::CUDADiscarded: + llvm_unreachable("CUDADiscarded unexpected in OpenMP device compilation"); + break; + } + + return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this); } -void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) { +Sema::DeviceDiagBuilder Sema::diagIfOpenMPHostCode(SourceLocation Loc, + unsigned DiagID) { + assert(LangOpts.OpenMP && !LangOpts.OpenMPIsDevice && + "Expected OpenMP host compilation."); + FunctionEmissionStatus FES = getEmissionStatus(getCurFunctionDecl()); + DeviceDiagBuilder::Kind Kind = DeviceDiagBuilder::K_Nop; + switch (FES) { + case FunctionEmissionStatus::Emitted: + Kind = DeviceDiagBuilder::K_Immediate; + break; + case FunctionEmissionStatus::Unknown: + Kind = DeviceDiagBuilder::K_Deferred; + break; + case FunctionEmissionStatus::TemplateDiscarded: + case FunctionEmissionStatus::OMPDiscarded: + case FunctionEmissionStatus::CUDADiscarded: + Kind = DeviceDiagBuilder::K_Nop; + break; + } + + return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this); +} + +void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee, + bool CheckForDelayedContext) { assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice && "Expected OpenMP device compilation."); assert(Callee && "Callee may not be null."); + Callee = Callee->getMostRecentDecl(); FunctionDecl *Caller = getCurFunctionDecl(); + // host only function are not available on the device. + if (Caller) { + FunctionEmissionStatus CallerS = getEmissionStatus(Caller); + FunctionEmissionStatus CalleeS = getEmissionStatus(Callee); + assert(CallerS != FunctionEmissionStatus::CUDADiscarded && + CalleeS != FunctionEmissionStatus::CUDADiscarded && + "CUDADiscarded unexpected in OpenMP device function check"); + if ((CallerS == FunctionEmissionStatus::Emitted || + (!isOpenMPDeviceDelayedContext(*this) && + CallerS == FunctionEmissionStatus::Unknown)) && + CalleeS == FunctionEmissionStatus::OMPDiscarded) { + StringRef HostDevTy = getOpenMPSimpleClauseTypeName( + OMPC_device_type, OMPC_DEVICE_TYPE_host); + Diag(Loc, diag::err_omp_wrong_device_function_call) << HostDevTy << 0; + Diag(Callee->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(), + diag::note_omp_marked_device_type_here) + << HostDevTy; + return; + } + } // If the caller is known-emitted, mark the callee as known-emitted. // Otherwise, mark the call in our call graph so we can traverse it later. - if (!isOpenMPDeviceDelayedContext(*this) || - (Caller && isKnownEmitted(*this, Caller))) - markKnownEmitted(*this, Caller, Callee, Loc, isKnownEmitted); + if ((CheckForDelayedContext && !isOpenMPDeviceDelayedContext(*this)) || + (!Caller && !CheckForDelayedContext) || + (Caller && getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted)) + markKnownEmitted(*this, Caller, Callee, Loc, + [CheckForDelayedContext](Sema &S, FunctionDecl *FD) { + return CheckForDelayedContext && + S.getEmissionStatus(FD) == + FunctionEmissionStatus::Emitted; + }); else if (Caller) DeviceCallGraph[Caller].insert({Callee, Loc}); } +void Sema::checkOpenMPHostFunction(SourceLocation Loc, FunctionDecl *Callee, + bool CheckCaller) { + assert(LangOpts.OpenMP && !LangOpts.OpenMPIsDevice && + "Expected OpenMP host compilation."); + assert(Callee && "Callee may not be null."); + Callee = Callee->getMostRecentDecl(); + FunctionDecl *Caller = getCurFunctionDecl(); + + // device only function are not available on the host. + if (Caller) { + FunctionEmissionStatus CallerS = getEmissionStatus(Caller); + FunctionEmissionStatus CalleeS = getEmissionStatus(Callee); + assert( + (LangOpts.CUDA || (CallerS != FunctionEmissionStatus::CUDADiscarded && + CalleeS != FunctionEmissionStatus::CUDADiscarded)) && + "CUDADiscarded unexpected in OpenMP host function check"); + if (CallerS == FunctionEmissionStatus::Emitted && + CalleeS == FunctionEmissionStatus::OMPDiscarded) { + StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName( + OMPC_device_type, OMPC_DEVICE_TYPE_nohost); + Diag(Loc, diag::err_omp_wrong_device_function_call) << NoHostDevTy << 1; + Diag(Callee->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(), + diag::note_omp_marked_device_type_here) + << NoHostDevTy; + return; + } + } + // If the caller is known-emitted, mark the callee as known-emitted. + // Otherwise, mark the call in our call graph so we can traverse it later. + if (!shouldIgnoreInHostDeviceCheck(Callee)) { + if ((!CheckCaller && !Caller) || + (Caller && + getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted)) + markKnownEmitted( + *this, Caller, Callee, Loc, [CheckCaller](Sema &S, FunctionDecl *FD) { + return CheckCaller && + S.getEmissionStatus(FD) == FunctionEmissionStatus::Emitted; + }); + else if (Caller) + DeviceCallGraph[Caller].insert({Callee, Loc}); + } +} + void Sema::checkOpenMPDeviceExpr(const Expr *E) { assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && "OpenMP device compilation mode is expected."); @@ -1598,7 +1716,8 @@ void Sema::checkOpenMPDeviceExpr(const Expr *E) { << Context.getTargetInfo().getTriple().str() << E->getSourceRange(); } -bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const { +bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level, + unsigned OpenMPCaptureLevel) const { assert(LangOpts.OpenMP && "OpenMP is not allowed"); ASTContext &Ctx = getASTContext(); @@ -1608,6 +1727,7 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const { D = cast<ValueDecl>(D->getCanonicalDecl()); QualType Ty = D->getType(); + bool IsVariableUsedInMapClause = false; if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level)) { // This table summarizes how a given variable should be passed to the device // given its type and the clauses where it appears. This table is based on @@ -1669,7 +1789,6 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const { // Locate map clauses and see if the variable being captured is referred to // in any of those clauses. Here we only care about variables, not fields, // because fields are part of aggregates. - bool IsVariableUsedInMapClause = false; bool IsVariableAssociatedWithSection = false; DSAStack->checkMappableExprComponentListsForDeclAtLevel( @@ -1727,10 +1846,13 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const { if (IsByRef && Ty.getNonReferenceType()->isScalarType()) { IsByRef = - !DSAStack->hasExplicitDSA( - D, - [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; }, - Level, /*NotLastprivate=*/true) && + ((IsVariableUsedInMapClause && + DSAStack->getCaptureRegion(Level, OpenMPCaptureLevel) == + OMPD_target) || + !DSAStack->hasExplicitDSA( + D, + [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; }, + Level, /*NotLastprivate=*/true)) && // If the variable is artificial and must be captured by value - try to // capture by value. !(isa<OMPCapturedExprDecl>(D) && !D->hasAttr<OMPCaptureNoInitAttr>() && @@ -1788,7 +1910,8 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo, if (isInOpenMPDeclareTargetContext()) { // Try to mark variable as declare target if it is used in capturing // regions. - if (!OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) + if (LangOpts.OpenMP <= 45 && + !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) checkDeclIsAllowedInOpenMPTarget(nullptr, VD); return nullptr; } else if (isInOpenMPTargetExecutionDirective()) { @@ -1858,6 +1981,14 @@ void Sema::startOpenMPLoop() { DSAStack->loopInit(); } +void Sema::startOpenMPCXXRangeFor() { + assert(LangOpts.OpenMP && "OpenMP must be enabled."); + if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) { + DSAStack->resetPossibleLoopCounter(); + DSAStack->loopStart(); + } +} + bool Sema::isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const { assert(LangOpts.OpenMP && "OpenMP is not allowed"); if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) { @@ -1874,6 +2005,13 @@ bool Sema::isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const { !isOpenMPSimdDirective(DSAStack->getCurrentDirective())) return true; } + if (const auto *VD = dyn_cast<VarDecl>(D)) { + if (DSAStack->isThreadPrivate(const_cast<VarDecl *>(VD)) && + DSAStack->isForceVarCapturing() && + !DSAStack->hasExplicitDSA( + D, [](OpenMPClauseKind K) { return K == OMPC_copyin; }, Level)) + return true; + } return DSAStack->hasExplicitDSA( D, [](OpenMPClauseKind K) { return K == OMPC_private; }, Level) || (DSAStack->isClauseParsingMode() && @@ -1937,6 +2075,54 @@ bool Sema::isOpenMPTargetCapturedDecl(const ValueDecl *D, void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; } +void Sema::finalizeOpenMPDelayedAnalysis() { + assert(LangOpts.OpenMP && "Expected OpenMP compilation mode."); + // Diagnose implicit declare target functions and their callees. + for (const auto &CallerCallees : DeviceCallGraph) { + Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + OMPDeclareTargetDeclAttr::getDeviceType( + CallerCallees.getFirst()->getMostRecentDecl()); + // Ignore host functions during device analyzis. + if (LangOpts.OpenMPIsDevice && DevTy && + *DevTy == OMPDeclareTargetDeclAttr::DT_Host) + continue; + // Ignore nohost functions during host analyzis. + if (!LangOpts.OpenMPIsDevice && DevTy && + *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) + continue; + for (const std::pair<CanonicalDeclPtr<FunctionDecl>, SourceLocation> + &Callee : CallerCallees.getSecond()) { + const FunctionDecl *FD = Callee.first->getMostRecentDecl(); + Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + OMPDeclareTargetDeclAttr::getDeviceType(FD); + if (LangOpts.OpenMPIsDevice && DevTy && + *DevTy == OMPDeclareTargetDeclAttr::DT_Host) { + // Diagnose host function called during device codegen. + StringRef HostDevTy = getOpenMPSimpleClauseTypeName( + OMPC_device_type, OMPC_DEVICE_TYPE_host); + Diag(Callee.second, diag::err_omp_wrong_device_function_call) + << HostDevTy << 0; + Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(), + diag::note_omp_marked_device_type_here) + << HostDevTy; + continue; + } + if (!LangOpts.OpenMPIsDevice && DevTy && + *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) { + // Diagnose nohost function called during host codegen. + StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName( + OMPC_device_type, OMPC_DEVICE_TYPE_nohost); + Diag(Callee.second, diag::err_omp_wrong_device_function_call) + << NoHostDevTy << 1; + Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(), + diag::note_omp_marked_device_type_here) + << NoHostDevTy; + continue; + } + } + } +} + void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName, Scope *CurScope, SourceLocation Loc) { @@ -2034,7 +2220,7 @@ public: } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<VarDeclFilterCCC>(*this); + return std::make_unique<VarDeclFilterCCC>(*this); } }; @@ -2056,7 +2242,7 @@ public: } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<VarOrFuncDeclFilterCCC>(*this); + return std::make_unique<VarOrFuncDeclFilterCCC>(*this); } }; @@ -2944,18 +3130,19 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); + Params, /*OpenMPCaptureLevel=*/0); // Mark this captured region as inlined, because we don't use outlined // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AttributeCommonInfo::AS_Keyword, + AlwaysInlineAttr::Keyword_forceinline)); Sema::CapturedParamNameType ParamsTarget[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; // Start a captured region for 'target' with no implicit parameters. ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - ParamsTarget); + ParamsTarget, /*OpenMPCaptureLevel=*/1); Sema::CapturedParamNameType ParamsTeamsOrParallel[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), std::make_pair(".bound_tid.", KmpInt32PtrTy), @@ -2964,7 +3151,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // Start a captured region for 'teams' or 'parallel'. Both regions have // the same implicit parameters. ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - ParamsTeamsOrParallel); + ParamsTeamsOrParallel, /*OpenMPCaptureLevel=*/2); break; } case OMPD_target: @@ -2988,14 +3175,16 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); + Params, /*OpenMPCaptureLevel=*/0); // Mark this captured region as inlined, because we don't use outlined // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AttributeCommonInfo::AS_Keyword, + AlwaysInlineAttr::Keyword_forceinline)); ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - std::make_pair(StringRef(), QualType())); + std::make_pair(StringRef(), QualType()), + /*OpenMPCaptureLevel=*/1); break; } case OMPD_simd: @@ -3044,11 +3233,14 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AttributeCommonInfo::AS_Keyword, + AlwaysInlineAttr::Keyword_forceinline)); break; } case OMPD_taskloop: - case OMPD_taskloop_simd: { + case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1) .withConst(); @@ -3086,7 +3278,58 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AttributeCommonInfo::AS_Keyword, + AlwaysInlineAttr::Keyword_forceinline)); + break; + } + case OMPD_parallel_master_taskloop: { + QualType KmpInt32Ty = + Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1) + .withConst(); + QualType KmpUInt64Ty = + Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0) + .withConst(); + QualType KmpInt64Ty = + Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1) + .withConst(); + QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict(); + QualType KmpInt32PtrTy = + Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); + Sema::CapturedParamNameType ParamsParallel[] = { + std::make_pair(".global_tid.", KmpInt32PtrTy), + std::make_pair(".bound_tid.", KmpInt32PtrTy), + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + // Start a captured region for 'parallel'. + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + ParamsParallel, /*OpenMPCaptureLevel=*/1); + QualType Args[] = {VoidPtrTy}; + FunctionProtoType::ExtProtoInfo EPI; + EPI.Variadic = true; + QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI); + Sema::CapturedParamNameType Params[] = { + std::make_pair(".global_tid.", KmpInt32Ty), + std::make_pair(".part_id.", KmpInt32PtrTy), + std::make_pair(".privates.", VoidPtrTy), + std::make_pair( + ".copy_fn.", + Context.getPointerType(CopyFnType).withConst().withRestrict()), + std::make_pair(".task_t.", Context.VoidPtrTy.withConst()), + std::make_pair(".lb.", KmpUInt64Ty), + std::make_pair(".ub.", KmpUInt64Ty), + std::make_pair(".st.", KmpInt64Ty), + std::make_pair(".liter.", KmpInt32Ty), + std::make_pair(".reductions.", VoidPtrTy), + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params, /*OpenMPCaptureLevel=*/2); + // Mark this captured region as inlined, because we don't use outlined + // function directly. + getCurCapturedRegion()->TheCapturedDecl->addAttr( + AlwaysInlineAttr::CreateImplicit( + Context, {}, AttributeCommonInfo::AS_Keyword, + AlwaysInlineAttr::Keyword_forceinline)); break; } case OMPD_distribute_parallel_for_simd: @@ -3127,18 +3370,19 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); + Params, /*OpenMPCaptureLevel=*/0); // Mark this captured region as inlined, because we don't use outlined // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AttributeCommonInfo::AS_Keyword, + AlwaysInlineAttr::Keyword_forceinline)); Sema::CapturedParamNameType ParamsTarget[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; // Start a captured region for 'target' with no implicit parameters. ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - ParamsTarget); + ParamsTarget, /*OpenMPCaptureLevel=*/1); Sema::CapturedParamNameType ParamsTeams[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), @@ -3147,7 +3391,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { }; // Start a captured region for 'target' with no implicit parameters. ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - ParamsTeams); + ParamsTeams, /*OpenMPCaptureLevel=*/2); Sema::CapturedParamNameType ParamsParallel[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), @@ -3159,7 +3403,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // Start a captured region for 'teams' or 'parallel'. Both regions have // the same implicit parameters. ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - ParamsParallel); + ParamsParallel, /*OpenMPCaptureLevel=*/3); break; } @@ -3176,7 +3420,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { }; // Start a captured region for 'target' with no implicit parameters. ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - ParamsTeams); + ParamsTeams, /*OpenMPCaptureLevel=*/0); Sema::CapturedParamNameType ParamsParallel[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), @@ -3188,7 +3432,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // Start a captured region for 'teams' or 'parallel'. Both regions have // the same implicit parameters. ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - ParamsParallel); + ParamsParallel, /*OpenMPCaptureLevel=*/1); break; } case OMPD_target_update: @@ -3218,7 +3462,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AttributeCommonInfo::AS_Keyword, + AlwaysInlineAttr::Keyword_forceinline)); break; } case OMPD_threadprivate: @@ -3235,12 +3480,17 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_requires: + case OMPD_declare_variant: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); } } +int Sema::getNumberOfConstructScopes(unsigned Level) const { + return getOpenMPCaptureLevels(DSAStack->getDirective(Level)); +} + int Sema::getOpenMPCaptureLevels(OpenMPDirectiveKind DKind) { SmallVector<OpenMPDirectiveKind, 4> CaptureRegions; getOpenMPCaptureRegions(CaptureRegions, DKind); @@ -3670,7 +3920,10 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, // OpenMP [2.16, Nesting of Regions] // If specified, a teams construct must be contained within a target // construct. - NestingProhibited = ParentRegion != OMPD_target; + NestingProhibited = + (SemaRef.LangOpts.OpenMP <= 45 && ParentRegion != OMPD_target) || + (SemaRef.LangOpts.OpenMP >= 50 && ParentRegion != OMPD_unknown && + ParentRegion != OMPD_target); OrphanSeen = ParentRegion == OMPD_unknown; Recommend = ShouldBeInTargetRegion; } @@ -4214,6 +4467,22 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( EndLoc, VarsWithInheritedDSA); AllowedNameModifiers.push_back(OMPD_taskloop); break; + case OMPD_master_taskloop: + Res = ActOnOpenMPMasterTaskLoopDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_taskloop); + break; + case OMPD_master_taskloop_simd: + Res = ActOnOpenMPMasterTaskLoopSimdDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_taskloop); + break; + case OMPD_parallel_master_taskloop: + Res = ActOnOpenMPParallelMasterTaskLoopDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_taskloop); + AllowedNameModifiers.push_back(OMPD_parallel); + break; case OMPD_distribute: Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); @@ -4301,6 +4570,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_requires: + case OMPD_declare_variant: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); @@ -4326,18 +4596,22 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( continue; case OMPC_schedule: break; + case OMPC_grainsize: + case OMPC_num_tasks: + case OMPC_final: + case OMPC_priority: + // Do not analyze if no parent parallel directive. + if (isOpenMPParallelDirective(DSAStack->getCurrentDirective())) + break; + continue; case OMPC_ordered: case OMPC_device: case OMPC_num_teams: case OMPC_thread_limit: - case OMPC_priority: - case OMPC_grainsize: - case OMPC_num_tasks: case OMPC_hint: case OMPC_collapse: case OMPC_safelen: case OMPC_simdlen: - case OMPC_final: case OMPC_default: case OMPC_proc_bind: case OMPC_private: @@ -4381,6 +4655,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_atomic_default_mem_order: + case OMPC_device_type: + case OMPC_match: llvm_unreachable("Unexpected clause"); } for (Stmt *CC : C->children()) { @@ -4437,8 +4713,10 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( if (!DG || DG.get().isNull()) return DeclGroupPtrTy(); + const int SimdId = 0; if (!DG.get().isSingleDecl()) { - Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd); + Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd_variant) + << SimdId; return DG; } Decl *ADecl = DG.get().getSingleDecl(); @@ -4447,7 +4725,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( auto *FD = dyn_cast<FunctionDecl>(ADecl); if (!FD) { - Diag(ADecl->getLocation(), diag::err_omp_function_expected); + Diag(ADecl->getLocation(), diag::err_omp_function_expected) << SimdId; return DeclGroupPtrTy(); } @@ -4669,7 +4947,266 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( const_cast<unsigned *>(LinModifiers.data()), LinModifiers.size(), NewSteps.data(), NewSteps.size(), SR); ADecl->addAttr(NewAttr); - return ConvertDeclToDeclGroup(ADecl); + return DG; +} + +Optional<std::pair<FunctionDecl *, Expr *>> +Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, + Expr *VariantRef, SourceRange SR) { + if (!DG || DG.get().isNull()) + return None; + + const int VariantId = 1; + // Must be applied only to single decl. + if (!DG.get().isSingleDecl()) { + Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd_variant) + << VariantId << SR; + return None; + } + Decl *ADecl = DG.get().getSingleDecl(); + if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ADecl)) + ADecl = FTD->getTemplatedDecl(); + + // Decl must be a function. + auto *FD = dyn_cast<FunctionDecl>(ADecl); + if (!FD) { + Diag(ADecl->getLocation(), diag::err_omp_function_expected) + << VariantId << SR; + return None; + } + + auto &&HasMultiVersionAttributes = [](const FunctionDecl *FD) { + return FD->hasAttrs() && + (FD->hasAttr<CPUDispatchAttr>() || FD->hasAttr<CPUSpecificAttr>() || + FD->hasAttr<TargetAttr>()); + }; + // OpenMP is not compatible with CPU-specific attributes. + if (HasMultiVersionAttributes(FD)) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_incompat_attributes) + << SR; + return None; + } + + // Allow #pragma omp declare variant only if the function is not used. + if (FD->isUsed(false)) + Diag(SR.getBegin(), diag::warn_omp_declare_variant_after_used) + << FD->getLocation(); + + // Check if the function was emitted already. + const FunctionDecl *Definition; + if (!FD->isThisDeclarationADefinition() && FD->isDefined(Definition) && + (LangOpts.EmitAllDecls || Context.DeclMustBeEmitted(Definition))) + Diag(SR.getBegin(), diag::warn_omp_declare_variant_after_emitted) + << FD->getLocation(); + + // The VariantRef must point to function. + if (!VariantRef) { + Diag(SR.getBegin(), diag::err_omp_function_expected) << VariantId; + return None; + } + + // Do not check templates, wait until instantiation. + if (VariantRef->isTypeDependent() || VariantRef->isValueDependent() || + VariantRef->containsUnexpandedParameterPack() || + VariantRef->isInstantiationDependent() || FD->isDependentContext()) + return std::make_pair(FD, VariantRef); + + // Convert VariantRef expression to the type of the original function to + // resolve possible conflicts. + ExprResult VariantRefCast; + if (LangOpts.CPlusPlus) { + QualType FnPtrType; + auto *Method = dyn_cast<CXXMethodDecl>(FD); + if (Method && !Method->isStatic()) { + const Type *ClassType = + Context.getTypeDeclType(Method->getParent()).getTypePtr(); + FnPtrType = Context.getMemberPointerType(FD->getType(), ClassType); + ExprResult ER; + { + // Build adrr_of unary op to correctly handle type checks for member + // functions. + Sema::TentativeAnalysisScope Trap(*this); + ER = CreateBuiltinUnaryOp(VariantRef->getBeginLoc(), UO_AddrOf, + VariantRef); + } + if (!ER.isUsable()) { + Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected) + << VariantId << VariantRef->getSourceRange(); + return None; + } + VariantRef = ER.get(); + } else { + FnPtrType = Context.getPointerType(FD->getType()); + } + ImplicitConversionSequence ICS = + TryImplicitConversion(VariantRef, FnPtrType.getUnqualifiedType(), + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*InOverloadResolution=*/false, + /*CStyle=*/false, + /*AllowObjCWritebackConversion=*/false); + if (ICS.isFailure()) { + Diag(VariantRef->getExprLoc(), + diag::err_omp_declare_variant_incompat_types) + << VariantRef->getType() << FnPtrType << VariantRef->getSourceRange(); + return None; + } + VariantRefCast = PerformImplicitConversion( + VariantRef, FnPtrType.getUnqualifiedType(), AA_Converting); + if (!VariantRefCast.isUsable()) + return None; + // Drop previously built artificial addr_of unary op for member functions. + if (Method && !Method->isStatic()) { + Expr *PossibleAddrOfVariantRef = VariantRefCast.get(); + if (auto *UO = dyn_cast<UnaryOperator>( + PossibleAddrOfVariantRef->IgnoreImplicit())) + VariantRefCast = UO->getSubExpr(); + } + } else { + VariantRefCast = VariantRef; + } + + ExprResult ER = CheckPlaceholderExpr(VariantRefCast.get()); + if (!ER.isUsable() || + !ER.get()->IgnoreParenImpCasts()->getType()->isFunctionType()) { + Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected) + << VariantId << VariantRef->getSourceRange(); + return None; + } + + // The VariantRef must point to function. + auto *DRE = dyn_cast<DeclRefExpr>(ER.get()->IgnoreParenImpCasts()); + if (!DRE) { + Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected) + << VariantId << VariantRef->getSourceRange(); + return None; + } + auto *NewFD = dyn_cast_or_null<FunctionDecl>(DRE->getDecl()); + if (!NewFD) { + Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected) + << VariantId << VariantRef->getSourceRange(); + return None; + } + + // Check if variant function is not marked with declare variant directive. + if (NewFD->hasAttrs() && NewFD->hasAttr<OMPDeclareVariantAttr>()) { + Diag(VariantRef->getExprLoc(), + diag::warn_omp_declare_variant_marked_as_declare_variant) + << VariantRef->getSourceRange(); + SourceRange SR = + NewFD->specific_attr_begin<OMPDeclareVariantAttr>()->getRange(); + Diag(SR.getBegin(), diag::note_omp_marked_declare_variant_here) << SR; + return None; + } + + enum DoesntSupport { + VirtFuncs = 1, + Constructors = 3, + Destructors = 4, + DeletedFuncs = 5, + DefaultedFuncs = 6, + ConstexprFuncs = 7, + ConstevalFuncs = 8, + }; + if (const auto *CXXFD = dyn_cast<CXXMethodDecl>(FD)) { + if (CXXFD->isVirtual()) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) + << VirtFuncs; + return None; + } + + if (isa<CXXConstructorDecl>(FD)) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) + << Constructors; + return None; + } + + if (isa<CXXDestructorDecl>(FD)) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) + << Destructors; + return None; + } + } + + if (FD->isDeleted()) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) + << DeletedFuncs; + return None; + } + + if (FD->isDefaulted()) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) + << DefaultedFuncs; + return None; + } + + if (FD->isConstexpr()) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) + << (NewFD->isConsteval() ? ConstevalFuncs : ConstexprFuncs); + return None; + } + + // 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), + PartialDiagnosticAt( + VariantRef->getExprLoc(), + PDiag(diag::err_omp_declare_variant_doesnt_support)), + PartialDiagnosticAt(VariantRef->getExprLoc(), + PDiag(diag::err_omp_declare_variant_diff) + << FD->getLocation()), + /*TemplatesSupported=*/true, /*ConstexprSupported=*/false, + /*CLinkageMayDiffer=*/true)) + return None; + return std::make_pair(FD, cast<Expr>(DRE)); +} + +void Sema::ActOnOpenMPDeclareVariantDirective( + FunctionDecl *FD, Expr *VariantRef, SourceRange SR, + const Sema::OpenMPDeclareVariantCtsSelectorData &Data) { + if (Data.CtxSet == OMPDeclareVariantAttr::CtxSetUnknown || + Data.Ctx == OMPDeclareVariantAttr::CtxUnknown) + 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; + } + } + 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, + FunctionDecl *Func, + bool MightBeOdrUse) { + assert(LangOpts.OpenMP && "Expected OpenMP mode."); + + if (!Func->isDependentContext() && Func->hasAttrs()) { + for (OMPDeclareVariantAttr *A : + 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 *F = cast<FunctionDecl>(DRE->getDecl()); + if (!F->isDefined() && F->isTemplateInstantiation()) + InstantiateFunctionDefinition(Loc, F->getFirstDecl()); + MarkFunctionReferenced(Loc, F, MightBeOdrUse); + } + } } StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, @@ -4694,6 +5231,54 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, } namespace { +/// Iteration space of a single for loop. +struct LoopIterationSpace final { + /// True if the condition operator is the strict compare operator (<, > or + /// !=). + bool IsStrictCompare = false; + /// Condition of the loop. + Expr *PreCond = nullptr; + /// This expression calculates the number of iterations in the loop. + /// It is always possible to calculate it before starting the loop. + Expr *NumIterations = nullptr; + /// The loop counter variable. + Expr *CounterVar = nullptr; + /// Private loop counter variable. + Expr *PrivateCounterVar = nullptr; + /// This is initializer for the initial value of #CounterVar. + Expr *CounterInit = nullptr; + /// This is step for the #CounterVar used to generate its update: + /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration. + Expr *CounterStep = nullptr; + /// Should step be subtracted? + bool Subtract = false; + /// Source range of the loop init. + SourceRange InitSrcRange; + /// Source range of the loop condition. + SourceRange CondSrcRange; + /// Source range of the loop increment. + SourceRange IncSrcRange; + /// Minimum value that can have the loop control variable. Used to support + /// non-rectangular loops. Applied only for LCV with the non-iterator types, + /// since only such variables can be used in non-loop invariant expressions. + Expr *MinValue = nullptr; + /// Maximum value that can have the loop control variable. Used to support + /// non-rectangular loops. Applied only for LCV with the non-iterator type, + /// since only such variables can be used in non-loop invariant expressions. + Expr *MaxValue = nullptr; + /// true, if the lower bound depends on the outer loop control var. + bool IsNonRectangularLB = false; + /// true, if the upper bound depends on the outer loop control var. + bool IsNonRectangularUB = false; + /// Index of the loop this loop depends on and forms non-rectangular loop + /// nest. + unsigned LoopDependentIdx = 0; + /// Final condition for the non-rectangular loop nest support. It is used to + /// check that the number of iterations for this particular counter must be + /// finished. + Expr *FinalCondition = nullptr; +}; + /// Helper class for checking canonical form of the OpenMP loops and /// extracting iteration space of each loop in the loop nest, that will be used /// for IR generation. @@ -4743,6 +5328,9 @@ class OpenMPIterationSpaceChecker { Optional<unsigned> CondDependOnLC; /// Checks if the provide statement depends on the loop counter. Optional<unsigned> doesDependOnLoopCounter(const Stmt *S, bool IsInitializer); + /// Original condition required for checking of the exit condition for + /// non-rectangular loop. + Expr *Condition = nullptr; public: OpenMPIterationSpaceChecker(Sema &SemaRef, DSAStackTy &Stack, @@ -4774,7 +5362,7 @@ public: bool isStrictTestOp() const { return TestIsStrictOp; } /// Build the expression to calculate the number of iterations. Expr *buildNumIterations( - Scope *S, const bool LimitedType, + Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const; /// Build the precondition expression for the loops. Expr * @@ -4798,8 +5386,21 @@ public: llvm::MapVector<const Expr *, DeclRefExpr *> &Captures, SourceLocation Loc, Expr *Inc = nullptr, OverloadedOperatorKind OOK = OO_Amp); + /// Builds the minimum value for the loop counter. + std::pair<Expr *, Expr *> buildMinMaxValues( + Scope *S, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const; + /// Builds final condition for the non-rectangular loops. + Expr *buildFinalCondition(Scope *S) const; /// Return true if any expression is dependent. bool dependent() const; + /// Returns true if the initializer forms non-rectangular loop. + bool doesInitDependOnLC() const { return InitDependOnLC.hasValue(); } + /// Returns true if the condition forms non-rectangular loop. + bool doesCondDependOnLC() const { return CondDependOnLC.hasValue(); } + /// Returns index of the loop we depend on (starting from 1), or 0 otherwise. + unsigned getLoopDependentIdx() const { + return InitDependOnLC.getValueOr(CondDependOnLC.getValueOr(0)); + } private: /// Check the right-hand side of an assignment in the increment @@ -4998,9 +5599,9 @@ public: return false; } bool VisitStmt(const Stmt *S) { - bool Res = true; + bool Res = false; for (const Stmt *Child : S->children()) - Res = Child && Visit(Child) && Res; + Res = (Child && Visit(Child)) || Res; return Res; } explicit LoopCounterRefChecker(Sema &SemaRef, DSAStackTy &Stack, @@ -5142,14 +5743,17 @@ static const ValueDecl *getInitLCDecl(const Expr *E) { bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) { // Check test-expr for canonical form, save upper-bound UB, flags for // less/greater and for strict/non-strict comparison. - // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following: + // OpenMP [2.9] Canonical loop form. Test-expr may be one of the following: // var relational-op b // b relational-op var // + bool IneqCondIsCanonical = SemaRef.getLangOpts().OpenMP >= 50; if (!S) { - SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << LCDecl; + SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) + << (IneqCondIsCanonical ? 1 : 0) << LCDecl; return true; } + Condition = S; S = getExprAsWritten(S); SourceLocation CondLoc = S->getBeginLoc(); if (auto *BO = dyn_cast<BinaryOperator>(S)) { @@ -5164,12 +5768,11 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) { (BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE), (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), BO->getSourceRange(), BO->getOperatorLoc()); - } else if (BO->getOpcode() == BO_NE) - return setUB(getInitLCDecl(BO->getLHS()) == LCDecl ? - BO->getRHS() : BO->getLHS(), - /*LessOp=*/llvm::None, - /*StrictOp=*/true, - BO->getSourceRange(), BO->getOperatorLoc()); + } else if (IneqCondIsCanonical && BO->getOpcode() == BO_NE) + return setUB( + getInitLCDecl(BO->getLHS()) == LCDecl ? BO->getRHS() : BO->getLHS(), + /*LessOp=*/llvm::None, + /*StrictOp=*/true, BO->getSourceRange(), BO->getOperatorLoc()); } else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(S)) { if (CE->getNumArgs() == 2) { auto Op = CE->getOperator(); @@ -5188,12 +5791,12 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) { CE->getOperatorLoc()); break; case OO_ExclaimEqual: - return setUB(getInitLCDecl(CE->getArg(0)) == LCDecl ? - CE->getArg(1) : CE->getArg(0), - /*LessOp=*/llvm::None, - /*StrictOp=*/true, - CE->getSourceRange(), - CE->getOperatorLoc()); + if (IneqCondIsCanonical) + return setUB(getInitLCDecl(CE->getArg(0)) == LCDecl ? CE->getArg(1) + : CE->getArg(0), + /*LessOp=*/llvm::None, + /*StrictOp=*/true, CE->getSourceRange(), + CE->getOperatorLoc()); break; default: break; @@ -5203,7 +5806,7 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) { if (dependent() || SemaRef.CurContext->isDependentContext()) return false; SemaRef.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond) - << S->getSourceRange() << LCDecl; + << (IneqCondIsCanonical ? 1 : 0) << S->getSourceRange() << LCDecl; return true; } @@ -5336,15 +5939,177 @@ tryBuildCapture(Sema &SemaRef, Expr *Capture, /// Build the expression to calculate the number of iterations. Expr *OpenMPIterationSpaceChecker::buildNumIterations( - Scope *S, const bool LimitedType, + Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const { ExprResult Diff; QualType VarType = LCDecl->getType().getNonReferenceType(); if (VarType->isIntegerType() || VarType->isPointerType() || SemaRef.getLangOpts().CPlusPlus) { + Expr *LBVal = LB; + Expr *UBVal = UB; + // LB = TestIsLessOp.getValue() ? min(LB(MinVal), LB(MaxVal)) : + // max(LB(MinVal), LB(MaxVal)) + if (InitDependOnLC) { + const LoopIterationSpace &IS = + ResultIterSpaces[ResultIterSpaces.size() - 1 - + InitDependOnLC.getValueOr( + CondDependOnLC.getValueOr(0))]; + if (!IS.MinValue || !IS.MaxValue) + return nullptr; + // OuterVar = Min + ExprResult MinValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue); + if (!MinValue.isUsable()) + return nullptr; + + ExprResult LBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MinValue.get()); + if (!LBMinVal.isUsable()) + return nullptr; + // OuterVar = Min, LBVal + LBMinVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMinVal.get(), LBVal); + if (!LBMinVal.isUsable()) + return nullptr; + // (OuterVar = Min, LBVal) + LBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMinVal.get()); + if (!LBMinVal.isUsable()) + return nullptr; + + // OuterVar = Max + ExprResult MaxValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue); + if (!MaxValue.isUsable()) + return nullptr; + + ExprResult LBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MaxValue.get()); + if (!LBMaxVal.isUsable()) + return nullptr; + // OuterVar = Max, LBVal + LBMaxVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMaxVal.get(), LBVal); + if (!LBMaxVal.isUsable()) + return nullptr; + // (OuterVar = Max, LBVal) + LBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMaxVal.get()); + if (!LBMaxVal.isUsable()) + return nullptr; + + Expr *LBMin = tryBuildCapture(SemaRef, LBMinVal.get(), Captures).get(); + Expr *LBMax = tryBuildCapture(SemaRef, LBMaxVal.get(), Captures).get(); + if (!LBMin || !LBMax) + return nullptr; + // LB(MinVal) < LB(MaxVal) + ExprResult MinLessMaxRes = + SemaRef.BuildBinOp(S, DefaultLoc, BO_LT, LBMin, LBMax); + if (!MinLessMaxRes.isUsable()) + return nullptr; + Expr *MinLessMax = + tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures).get(); + if (!MinLessMax) + return nullptr; + if (TestIsLessOp.getValue()) { + // LB(MinVal) < LB(MaxVal) ? LB(MinVal) : LB(MaxVal) - min(LB(MinVal), + // LB(MaxVal)) + ExprResult MinLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc, + MinLessMax, LBMin, LBMax); + if (!MinLB.isUsable()) + return nullptr; + LBVal = MinLB.get(); + } else { + // LB(MinVal) < LB(MaxVal) ? LB(MaxVal) : LB(MinVal) - max(LB(MinVal), + // LB(MaxVal)) + ExprResult MaxLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc, + MinLessMax, LBMax, LBMin); + if (!MaxLB.isUsable()) + return nullptr; + LBVal = MaxLB.get(); + } + } + // UB = TestIsLessOp.getValue() ? max(UB(MinVal), UB(MaxVal)) : + // min(UB(MinVal), UB(MaxVal)) + if (CondDependOnLC) { + const LoopIterationSpace &IS = + ResultIterSpaces[ResultIterSpaces.size() - 1 - + InitDependOnLC.getValueOr( + CondDependOnLC.getValueOr(0))]; + if (!IS.MinValue || !IS.MaxValue) + return nullptr; + // OuterVar = Min + ExprResult MinValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue); + if (!MinValue.isUsable()) + return nullptr; + + ExprResult UBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MinValue.get()); + if (!UBMinVal.isUsable()) + return nullptr; + // OuterVar = Min, UBVal + UBMinVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMinVal.get(), UBVal); + if (!UBMinVal.isUsable()) + return nullptr; + // (OuterVar = Min, UBVal) + UBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMinVal.get()); + if (!UBMinVal.isUsable()) + return nullptr; + + // OuterVar = Max + ExprResult MaxValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue); + if (!MaxValue.isUsable()) + return nullptr; + + ExprResult UBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MaxValue.get()); + if (!UBMaxVal.isUsable()) + return nullptr; + // OuterVar = Max, UBVal + UBMaxVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMaxVal.get(), UBVal); + if (!UBMaxVal.isUsable()) + return nullptr; + // (OuterVar = Max, UBVal) + UBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMaxVal.get()); + if (!UBMaxVal.isUsable()) + return nullptr; + + Expr *UBMin = tryBuildCapture(SemaRef, UBMinVal.get(), Captures).get(); + Expr *UBMax = tryBuildCapture(SemaRef, UBMaxVal.get(), Captures).get(); + if (!UBMin || !UBMax) + return nullptr; + // UB(MinVal) > UB(MaxVal) + ExprResult MinGreaterMaxRes = + SemaRef.BuildBinOp(S, DefaultLoc, BO_GT, UBMin, UBMax); + if (!MinGreaterMaxRes.isUsable()) + return nullptr; + Expr *MinGreaterMax = + tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), Captures).get(); + if (!MinGreaterMax) + return nullptr; + if (TestIsLessOp.getValue()) { + // UB(MinVal) > UB(MaxVal) ? UB(MinVal) : UB(MaxVal) - max(UB(MinVal), + // UB(MaxVal)) + ExprResult MaxUB = SemaRef.ActOnConditionalOp( + DefaultLoc, DefaultLoc, MinGreaterMax, UBMin, UBMax); + if (!MaxUB.isUsable()) + return nullptr; + UBVal = MaxUB.get(); + } else { + // UB(MinVal) > UB(MaxVal) ? UB(MaxVal) : UB(MinVal) - min(UB(MinVal), + // UB(MaxVal)) + ExprResult MinUB = SemaRef.ActOnConditionalOp( + DefaultLoc, DefaultLoc, MinGreaterMax, UBMax, UBMin); + if (!MinUB.isUsable()) + return nullptr; + UBVal = MinUB.get(); + } + } // Upper - Lower - Expr *UBExpr = TestIsLessOp.getValue() ? UB : LB; - Expr *LBExpr = TestIsLessOp.getValue() ? LB : UB; + Expr *UBExpr = TestIsLessOp.getValue() ? UBVal : LBVal; + Expr *LBExpr = TestIsLessOp.getValue() ? LBVal : UBVal; Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get(); Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get(); if (!Upper || !Lower) @@ -5431,12 +6196,142 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations( return Diff.get(); } +std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues( + Scope *S, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const { + // Do not build for iterators, they cannot be used in non-rectangular loop + // nests. + if (LCDecl->getType()->isRecordType()) + return std::make_pair(nullptr, nullptr); + // If we subtract, the min is in the condition, otherwise the min is in the + // init value. + Expr *MinExpr = nullptr; + Expr *MaxExpr = nullptr; + Expr *LBExpr = TestIsLessOp.getValue() ? LB : UB; + Expr *UBExpr = TestIsLessOp.getValue() ? UB : LB; + bool LBNonRect = TestIsLessOp.getValue() ? InitDependOnLC.hasValue() + : CondDependOnLC.hasValue(); + bool UBNonRect = TestIsLessOp.getValue() ? CondDependOnLC.hasValue() + : InitDependOnLC.hasValue(); + Expr *Lower = + LBNonRect ? LBExpr : tryBuildCapture(SemaRef, LBExpr, Captures).get(); + Expr *Upper = + UBNonRect ? UBExpr : tryBuildCapture(SemaRef, UBExpr, Captures).get(); + if (!Upper || !Lower) + return std::make_pair(nullptr, nullptr); + + if (TestIsLessOp.getValue()) + MinExpr = Lower; + else + MaxExpr = Upper; + + // Build minimum/maximum value based on number of iterations. + ExprResult Diff; + QualType VarType = LCDecl->getType().getNonReferenceType(); + + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + // Upper - Lower [- 1] + if (TestIsStrictOp) + Diff = SemaRef.BuildBinOp( + S, DefaultLoc, BO_Sub, Diff.get(), + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + // Upper - Lower [- 1] + Step + ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures); + if (!NewStep.isUsable()) + return std::make_pair(nullptr, nullptr); + + // Parentheses (for dumping/debugging purposes only). + Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + // (Upper - Lower [- 1]) / Step + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + // ((Upper - Lower [- 1]) / Step) * Step + // Parentheses (for dumping/debugging purposes only). + Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Mul, Diff.get(), NewStep.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + // Convert to the original type or ptrdiff_t, if original type is pointer. + if (!VarType->isAnyPointerType() && + !SemaRef.Context.hasSameType(Diff.get()->getType(), VarType)) { + Diff = SemaRef.PerformImplicitConversion( + Diff.get(), VarType, Sema::AA_Converting, /*AllowExplicit=*/true); + } else if (VarType->isAnyPointerType() && + !SemaRef.Context.hasSameType( + Diff.get()->getType(), + SemaRef.Context.getUnsignedPointerDiffType())) { + Diff = SemaRef.PerformImplicitConversion( + Diff.get(), SemaRef.Context.getUnsignedPointerDiffType(), + Sema::AA_Converting, /*AllowExplicit=*/true); + } + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + // Parentheses (for dumping/debugging purposes only). + Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + if (TestIsLessOp.getValue()) { + // MinExpr = Lower; + // MaxExpr = Lower + (((Upper - Lower [- 1]) / Step) * Step) + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Lower, Diff.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + MaxExpr = Diff.get(); + } else { + // MaxExpr = Upper; + // MinExpr = Upper - (((Upper - Lower [- 1]) / Step) * Step) + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Diff.get()); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + MinExpr = Diff.get(); + } + + return std::make_pair(MinExpr, MaxExpr); +} + +Expr *OpenMPIterationSpaceChecker::buildFinalCondition(Scope *S) const { + if (InitDependOnLC || CondDependOnLC) + return Condition; + return nullptr; +} + Expr *OpenMPIterationSpaceChecker::buildPreCond( Scope *S, Expr *Cond, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const { + // Do not build a precondition when the condition/initialization is dependent + // to prevent pessimistic early loop exit. + // TODO: this can be improved by calculating min/max values but not sure that + // it will be very effective. + if (CondDependOnLC || InitDependOnLC) + return SemaRef.PerformImplicitConversion( + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get(), + SemaRef.Context.BoolTy, /*Action=*/Sema::AA_Casting, + /*AllowExplicit=*/true).get(); + // Try to build LB <op> UB, where <op> is <, >, <=, or >=. - bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics(); - SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true); + Sema::TentativeAnalysisScope Trap(SemaRef); ExprResult NewLB = tryBuildCapture(SemaRef, LB, Captures); ExprResult NewUB = tryBuildCapture(SemaRef, UB, Captures); @@ -5456,7 +6351,7 @@ Expr *OpenMPIterationSpaceChecker::buildPreCond( CondExpr.get(), SemaRef.Context.BoolTy, /*Action=*/Sema::AA_Casting, /*AllowExplicit=*/true); } - SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress); + // Otherwise use original loop condition and evaluate it in runtime. return CondExpr.isUsable() ? CondExpr.get() : Cond; } @@ -5561,36 +6456,6 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData( return Diff.get(); } - -/// Iteration space of a single for loop. -struct LoopIterationSpace final { - /// True if the condition operator is the strict compare operator (<, > or - /// !=). - bool IsStrictCompare = false; - /// Condition of the loop. - Expr *PreCond = nullptr; - /// This expression calculates the number of iterations in the loop. - /// It is always possible to calculate it before starting the loop. - Expr *NumIterations = nullptr; - /// The loop counter variable. - Expr *CounterVar = nullptr; - /// Private loop counter variable. - Expr *PrivateCounterVar = nullptr; - /// This is initializer for the initial value of #CounterVar. - Expr *CounterInit = nullptr; - /// This is step for the #CounterVar used to generate its update: - /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration. - Expr *CounterStep = nullptr; - /// Should step be subtracted? - bool Subtract = false; - /// Source range of the loop init. - SourceRange InitSrcRange; - /// Source range of the loop condition. - SourceRange CondSrcRange; - /// Source range of the loop increment. - SourceRange IncSrcRange; -}; - } // namespace void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { @@ -5604,13 +6469,14 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { if (!ISC.checkAndSetInit(Init, /*EmitDiags=*/false)) { if (ValueDecl *D = ISC.getLoopDecl()) { auto *VD = dyn_cast<VarDecl>(D); + DeclRefExpr *PrivateRef = nullptr; if (!VD) { if (VarDecl *Private = isOpenMPCapturedDecl(D)) { VD = Private; } else { - DeclRefExpr *Ref = buildCapture(*this, D, ISC.getLoopDeclRefExpr(), - /*WithInit=*/false); - VD = cast<VarDecl>(Ref->getDecl()); + PrivateRef = buildCapture(*this, D, ISC.getLoopDeclRefExpr(), + /*WithInit=*/false); + VD = cast<VarDecl>(PrivateRef->getDecl()); } } DSAStack->addLoopControlVariable(D, VD); @@ -5623,6 +6489,51 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { Var->getType().getNonLValueExprType(Context), ForLoc, /*RefersToCapture=*/true)); } + OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); + // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables + // Referenced in a Construct, C/C++]. The loop iteration variable in the + // associated for-loop of a simd construct with just one associated + // for-loop may be listed in a linear clause with a constant-linear-step + // that is the increment of the associated for-loop. The loop iteration + // variable(s) in the associated for-loop(s) of a for or parallel for + // construct may be listed in a private or lastprivate clause. + DSAStackTy::DSAVarData DVar = + DSAStack->getTopDSA(D, /*FromParent=*/false); + // If LoopVarRefExpr is nullptr it means the corresponding loop variable + // is declared in the loop and it is predetermined as a private. + Expr *LoopDeclRefExpr = ISC.getLoopDeclRefExpr(); + OpenMPClauseKind PredeterminedCKind = + isOpenMPSimdDirective(DKind) + ? (DSAStack->hasMutipleLoops() ? OMPC_lastprivate : OMPC_linear) + : OMPC_private; + if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && + DVar.CKind != PredeterminedCKind && DVar.RefExpr && + (LangOpts.OpenMP <= 45 || (DVar.CKind != OMPC_lastprivate && + DVar.CKind != OMPC_private))) || + ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop || + DKind == OMPD_master_taskloop || + DKind == OMPD_parallel_master_taskloop || + isOpenMPDistributeDirective(DKind)) && + !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && + DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) && + (DVar.CKind != OMPC_private || DVar.RefExpr)) { + Diag(Init->getBeginLoc(), diag::err_omp_loop_var_dsa) + << getOpenMPClauseName(DVar.CKind) + << getOpenMPDirectiveName(DKind) + << getOpenMPClauseName(PredeterminedCKind); + if (DVar.RefExpr == nullptr) + DVar.CKind = PredeterminedCKind; + reportOriginalDsa(*this, DSAStack, D, DVar, + /*IsLoopIterVar=*/true); + } else if (LoopDeclRefExpr) { + // Make the loop iteration variable private (for worksharing + // constructs), linear (for simd directives with the only one + // associated loop) or lastprivate (for simd directives with several + // collapsed or ordered loops). + if (DVar.CKind == OMPC_unknown) + DSAStack->addDSA(D, LoopDeclRefExpr, PredeterminedCKind, + PrivateRef); + } } } DSAStack->setAssociatedLoops(AssociatedLoops - 1); @@ -5637,12 +6548,15 @@ static bool checkOpenMPIterationSpace( unsigned TotalNestedLoopCount, Expr *CollapseLoopCountExpr, Expr *OrderedLoopCountExpr, Sema::VarsWithInheritedDSAType &VarsWithImplicitDSA, - LoopIterationSpace &ResultIterSpace, + llvm::MutableArrayRef<LoopIterationSpace> ResultIterSpaces, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) { - // OpenMP [2.6, Canonical Loop Form] + // OpenMP [2.9.1, Canonical Loop Form] // for (init-expr; test-expr; incr-expr) structured-block + // for (range-decl: range-expr) structured-block auto *For = dyn_cast_or_null<ForStmt>(S); - if (!For) { + auto *CXXFor = dyn_cast_or_null<CXXForRangeStmt>(S); + // Ranged for is supported only in OpenMP 5.0. + if (!For && (SemaRef.LangOpts.OpenMP <= 45 || !CXXFor)) { SemaRef.Diag(S->getBeginLoc(), diag::err_omp_not_for) << (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr) << getOpenMPDirectiveName(DKind) << TotalNestedLoopCount @@ -5664,12 +6578,14 @@ static bool checkOpenMPIterationSpace( } return true; } - assert(For->getBody()); + assert(((For && For->getBody()) || (CXXFor && CXXFor->getBody())) && + "No loop body."); - OpenMPIterationSpaceChecker ISC(SemaRef, DSA, For->getForLoc()); + OpenMPIterationSpaceChecker ISC(SemaRef, DSA, + For ? For->getForLoc() : CXXFor->getForLoc()); // Check init. - Stmt *Init = For->getInit(); + Stmt *Init = For ? For->getInit() : CXXFor->getBeginStmt(); if (ISC.checkAndSetInit(Init)) return true; @@ -5677,8 +6593,6 @@ static bool checkOpenMPIterationSpace( // Check loop variable's type. if (ValueDecl *LCDecl = ISC.getLoopDecl()) { - Expr *LoopDeclRefExpr = ISC.getLoopDeclRefExpr(); - // OpenMP [2.6, Canonical Loop Form] // Var is one of the following: // A variable of signed or unsigned integer type. @@ -5704,90 +6618,70 @@ static bool checkOpenMPIterationSpace( // sharing attributes. VarsWithImplicitDSA.erase(LCDecl); - // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced - // in a Construct, C/C++]. - // The loop iteration variable in the associated for-loop of a simd - // construct with just one associated for-loop may be listed in a linear - // clause with a constant-linear-step that is the increment of the - // associated for-loop. - // The loop iteration variable(s) in the associated for-loop(s) of a for or - // parallel for construct may be listed in a private or lastprivate clause. - DSAStackTy::DSAVarData DVar = DSA.getTopDSA(LCDecl, false); - // If LoopVarRefExpr is nullptr it means the corresponding loop variable is - // declared in the loop and it is predetermined as a private. - OpenMPClauseKind PredeterminedCKind = - isOpenMPSimdDirective(DKind) - ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate) - : OMPC_private; - if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && - DVar.CKind != PredeterminedCKind && DVar.RefExpr && - (SemaRef.getLangOpts().OpenMP <= 45 || - (DVar.CKind != OMPC_lastprivate && DVar.CKind != OMPC_private))) || - ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop || - isOpenMPDistributeDirective(DKind)) && - !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && - DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) && - (DVar.CKind != OMPC_private || DVar.RefExpr)) { - SemaRef.Diag(Init->getBeginLoc(), diag::err_omp_loop_var_dsa) - << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind) - << getOpenMPClauseName(PredeterminedCKind); - if (DVar.RefExpr == nullptr) - DVar.CKind = PredeterminedCKind; - reportOriginalDsa(SemaRef, &DSA, LCDecl, DVar, /*IsLoopIterVar=*/true); - HasErrors = true; - } else if (LoopDeclRefExpr != nullptr) { - // Make the loop iteration variable private (for worksharing constructs), - // linear (for simd directives with the only one associated loop) or - // lastprivate (for simd directives with several collapsed or ordered - // loops). - if (DVar.CKind == OMPC_unknown) - DSA.addDSA(LCDecl, LoopDeclRefExpr, PredeterminedCKind); - } - assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars"); // Check test-expr. - HasErrors |= ISC.checkAndSetCond(For->getCond()); + HasErrors |= ISC.checkAndSetCond(For ? For->getCond() : CXXFor->getCond()); // Check incr-expr. - HasErrors |= ISC.checkAndSetInc(For->getInc()); + HasErrors |= ISC.checkAndSetInc(For ? For->getInc() : CXXFor->getInc()); } if (ISC.dependent() || SemaRef.CurContext->isDependentContext() || HasErrors) return HasErrors; // Build the loop's iteration space representation. - ResultIterSpace.PreCond = - ISC.buildPreCond(DSA.getCurScope(), For->getCond(), Captures); - ResultIterSpace.NumIterations = ISC.buildNumIterations( - DSA.getCurScope(), - (isOpenMPWorksharingDirective(DKind) || - isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)), - Captures); - ResultIterSpace.CounterVar = ISC.buildCounterVar(Captures, DSA); - ResultIterSpace.PrivateCounterVar = ISC.buildPrivateCounterVar(); - ResultIterSpace.CounterInit = ISC.buildCounterInit(); - ResultIterSpace.CounterStep = ISC.buildCounterStep(); - ResultIterSpace.InitSrcRange = ISC.getInitSrcRange(); - ResultIterSpace.CondSrcRange = ISC.getConditionSrcRange(); - ResultIterSpace.IncSrcRange = ISC.getIncrementSrcRange(); - ResultIterSpace.Subtract = ISC.shouldSubtractStep(); - ResultIterSpace.IsStrictCompare = ISC.isStrictTestOp(); - - HasErrors |= (ResultIterSpace.PreCond == nullptr || - ResultIterSpace.NumIterations == nullptr || - ResultIterSpace.CounterVar == nullptr || - ResultIterSpace.PrivateCounterVar == nullptr || - ResultIterSpace.CounterInit == nullptr || - ResultIterSpace.CounterStep == nullptr); + ResultIterSpaces[CurrentNestedLoopCount].PreCond = ISC.buildPreCond( + DSA.getCurScope(), For ? For->getCond() : CXXFor->getCond(), Captures); + ResultIterSpaces[CurrentNestedLoopCount].NumIterations = + ISC.buildNumIterations(DSA.getCurScope(), ResultIterSpaces, + (isOpenMPWorksharingDirective(DKind) || + isOpenMPTaskLoopDirective(DKind) || + isOpenMPDistributeDirective(DKind)), + Captures); + ResultIterSpaces[CurrentNestedLoopCount].CounterVar = + ISC.buildCounterVar(Captures, DSA); + ResultIterSpaces[CurrentNestedLoopCount].PrivateCounterVar = + ISC.buildPrivateCounterVar(); + ResultIterSpaces[CurrentNestedLoopCount].CounterInit = ISC.buildCounterInit(); + ResultIterSpaces[CurrentNestedLoopCount].CounterStep = ISC.buildCounterStep(); + ResultIterSpaces[CurrentNestedLoopCount].InitSrcRange = ISC.getInitSrcRange(); + ResultIterSpaces[CurrentNestedLoopCount].CondSrcRange = + ISC.getConditionSrcRange(); + ResultIterSpaces[CurrentNestedLoopCount].IncSrcRange = + ISC.getIncrementSrcRange(); + ResultIterSpaces[CurrentNestedLoopCount].Subtract = ISC.shouldSubtractStep(); + ResultIterSpaces[CurrentNestedLoopCount].IsStrictCompare = + ISC.isStrictTestOp(); + std::tie(ResultIterSpaces[CurrentNestedLoopCount].MinValue, + ResultIterSpaces[CurrentNestedLoopCount].MaxValue) = + ISC.buildMinMaxValues(DSA.getCurScope(), Captures); + ResultIterSpaces[CurrentNestedLoopCount].FinalCondition = + ISC.buildFinalCondition(DSA.getCurScope()); + ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularLB = + ISC.doesInitDependOnLC(); + ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularUB = + ISC.doesCondDependOnLC(); + ResultIterSpaces[CurrentNestedLoopCount].LoopDependentIdx = + ISC.getLoopDependentIdx(); + + HasErrors |= + (ResultIterSpaces[CurrentNestedLoopCount].PreCond == nullptr || + ResultIterSpaces[CurrentNestedLoopCount].NumIterations == nullptr || + ResultIterSpaces[CurrentNestedLoopCount].CounterVar == nullptr || + ResultIterSpaces[CurrentNestedLoopCount].PrivateCounterVar == nullptr || + ResultIterSpaces[CurrentNestedLoopCount].CounterInit == nullptr || + ResultIterSpaces[CurrentNestedLoopCount].CounterStep == nullptr); if (!HasErrors && DSA.isOrderedRegion()) { if (DSA.getOrderedRegionParam().second->getNumForLoops()) { if (CurrentNestedLoopCount < DSA.getOrderedRegionParam().second->getLoopNumIterations().size()) { DSA.getOrderedRegionParam().second->setLoopNumIterations( - CurrentNestedLoopCount, ResultIterSpace.NumIterations); + CurrentNestedLoopCount, + ResultIterSpaces[CurrentNestedLoopCount].NumIterations); DSA.getOrderedRegionParam().second->setLoopCounter( - CurrentNestedLoopCount, ResultIterSpace.CounterVar); + CurrentNestedLoopCount, + ResultIterSpaces[CurrentNestedLoopCount].CounterVar); } } for (auto &Pair : DSA.getDoacrossDependClauses()) { @@ -5804,11 +6698,13 @@ static bool checkOpenMPIterationSpace( Expr *CntValue; if (Pair.first->getDependencyKind() == OMPC_DEPEND_source) CntValue = ISC.buildOrderedLoopData( - DSA.getCurScope(), ResultIterSpace.CounterVar, Captures, + DSA.getCurScope(), + ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures, Pair.first->getDependencyLoc()); else CntValue = ISC.buildOrderedLoopData( - DSA.getCurScope(), ResultIterSpace.CounterVar, Captures, + DSA.getCurScope(), + ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures, Pair.first->getDependencyLoc(), Pair.second[CurrentNestedLoopCount].first, Pair.second[CurrentNestedLoopCount].second); @@ -5822,10 +6718,12 @@ static bool checkOpenMPIterationSpace( /// Build 'VarRef = Start. static ExprResult buildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, - ExprResult Start, + ExprResult Start, bool IsNonRectangularLB, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) { // Build 'VarRef = Start. - ExprResult NewStart = tryBuildCapture(SemaRef, Start.get(), Captures); + ExprResult NewStart = IsNonRectangularLB + ? Start.get() + : tryBuildCapture(SemaRef, Start.get(), Captures); if (!NewStart.isUsable()) return ExprError(); if (!SemaRef.Context.hasSameType(NewStart.get()->getType(), @@ -5846,6 +6744,7 @@ buildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, static ExprResult buildCounterUpdate( Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, ExprResult Start, ExprResult Iter, ExprResult Step, bool Subtract, + bool IsNonRectangularLB, llvm::MapVector<const Expr *, DeclRefExpr *> *Captures = nullptr) { // Add parentheses (for debugging purposes only). Iter = SemaRef.ActOnParenExpr(Loc, Loc, Iter.get()); @@ -5865,8 +6764,12 @@ static ExprResult buildCounterUpdate( // Try to build 'VarRef = Start, VarRef (+|-)= Iter * Step' or // 'VarRef = Start (+|-) Iter * Step'. - ExprResult NewStart = Start; - if (Captures) + if (!Start.isUsable()) + return ExprError(); + ExprResult NewStart = SemaRef.ActOnParenExpr(Loc, Loc, Start.get()); + if (!NewStart.isUsable()) + return ExprError(); + if (Captures && !IsNonRectangularLB) NewStart = tryBuildCapture(SemaRef, Start.get(), *Captures); if (NewStart.isInvalid()) return ExprError(); @@ -5877,8 +6780,8 @@ static ExprResult buildCounterUpdate( if (VarRef.get()->getType()->isOverloadableType() || NewStart.get()->getType()->isOverloadableType() || Update.get()->getType()->isOverloadableType()) { - bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics(); - SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true); + Sema::TentativeAnalysisScope Trap(SemaRef); + Update = SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), NewStart.get()); if (Update.isUsable()) { @@ -5890,7 +6793,6 @@ static ExprResult buildCounterUpdate( UpdateVal.get()); } } - SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress); } // Second attempt: try to build 'VarRef = Start (+|-) Iter * Step'. @@ -6037,22 +6939,27 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, if (checkOpenMPIterationSpace( DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount, std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr, - OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces[Cnt], - Captures)) + OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces, Captures)) return 0; // Move on to the next nested for loop, or to the loop body. // OpenMP [2.8.1, simd construct, Restrictions] // All loops associated with the construct must be perfectly nested; that // is, there must be no intervening code nor any OpenMP directive between // any two loops. - CurStmt = cast<ForStmt>(CurStmt)->getBody()->IgnoreContainers(); + if (auto *For = dyn_cast<ForStmt>(CurStmt)) { + CurStmt = For->getBody(); + } else { + assert(isa<CXXForRangeStmt>(CurStmt) && + "Expected canonical for or range-based for loops."); + CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody(); + } + CurStmt = CurStmt->IgnoreContainers(); } for (unsigned Cnt = NestedLoopCount; Cnt < OrderedLoopCount; ++Cnt) { if (checkOpenMPIterationSpace( DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount, std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr, - OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces[Cnt], - Captures)) + OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces, Captures)) return 0; if (Cnt > 0 && IterSpaces[Cnt].CounterVar) { // Handle initialization of captured loop iterator variables. @@ -6066,7 +6973,14 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // All loops associated with the construct must be perfectly nested; that // is, there must be no intervening code nor any OpenMP directive between // any two loops. - CurStmt = cast<ForStmt>(CurStmt)->getBody()->IgnoreContainers(); + if (auto *For = dyn_cast<ForStmt>(CurStmt)) { + CurStmt = For->getBody(); + } else { + assert(isa<CXXForRangeStmt>(CurStmt) && + "Expected canonical for or range-based for loops."); + CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody(); + } + CurStmt = CurStmt->IgnoreContainers(); } Built.clear(/* size */ NestedLoopCount); @@ -6513,6 +7427,9 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Built.Inits.resize(NestedLoopCount); Built.Updates.resize(NestedLoopCount); Built.Finals.resize(NestedLoopCount); + Built.DependentCounters.resize(NestedLoopCount); + Built.DependentInits.resize(NestedLoopCount); + Built.FinalsConditions.resize(NestedLoopCount); { // We implement the following algorithm for obtaining the // original loop iteration variable values based on the @@ -6572,24 +7489,26 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, DeclRefExpr *CounterVar = buildDeclRefExpr( SemaRef, VD, IS.CounterVar->getType(), IS.CounterVar->getExprLoc(), /*RefersToCapture=*/true); - ExprResult Init = buildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar, - IS.CounterInit, Captures); + ExprResult Init = + buildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar, + IS.CounterInit, IS.IsNonRectangularLB, Captures); if (!Init.isUsable()) { HasErrors = true; break; } ExprResult Update = buildCounterUpdate( SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, Iter, - IS.CounterStep, IS.Subtract, &Captures); + IS.CounterStep, IS.Subtract, IS.IsNonRectangularLB, &Captures); if (!Update.isUsable()) { HasErrors = true; break; } // Build final: IS.CounterVar = IS.Start + IS.NumIters * IS.Step - ExprResult Final = buildCounterUpdate( - SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, - IS.NumIterations, IS.CounterStep, IS.Subtract, &Captures); + ExprResult Final = + buildCounterUpdate(SemaRef, CurScope, UpdLoc, CounterVar, + IS.CounterInit, IS.NumIterations, IS.CounterStep, + IS.Subtract, IS.IsNonRectangularLB, &Captures); if (!Final.isUsable()) { HasErrors = true; break; @@ -6605,6 +7524,16 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Built.Inits[Cnt] = Init.get(); Built.Updates[Cnt] = Update.get(); Built.Finals[Cnt] = Final.get(); + Built.DependentCounters[Cnt] = nullptr; + Built.DependentInits[Cnt] = nullptr; + Built.FinalsConditions[Cnt] = nullptr; + if (IS.IsNonRectangularLB || IS.IsNonRectangularUB) { + Built.DependentCounters[Cnt] = + Built.Counters[NestedLoopCount - 1 - IS.LoopDependentIdx]; + Built.DependentInits[Cnt] = + Built.Inits[NestedLoopCount - 1 - IS.LoopDependentIdx]; + Built.FinalsConditions[Cnt] = IS.FinalCondition; + } } } @@ -6617,7 +7546,7 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Built.NumIterations = NumIterations.get(); Built.CalcLastIteration = SemaRef .ActOnFinishFullExpr(CalcLastIteration.get(), - /*DiscardedValue*/ false) + /*DiscardedValue=*/false) .get(); Built.PreCond = PreCond.get(); Built.PreInits = buildPreInits(C, Captures); @@ -8398,6 +9327,146 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( NestedLoopCount, Clauses, AStmt, B); } +StmtResult Sema::ActOnOpenMPMasterTaskLoopDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); + 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_master_taskloop, getCollapseNumberExpr(Clauses), + /*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack, + VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp for loop exprs were not built"); + + // OpenMP, [2.9.2 taskloop Construct, Restrictions] + // The grainsize clause and num_tasks clause are mutually exclusive and may + // not appear on the same taskloop directive. + if (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(); + + setFunctionHasBranchProtectedScope(); + return OMPMasterTaskLoopDirective::Create(Context, StartLoc, EndLoc, + NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPMasterTaskLoopSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); + 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_master_taskloop_simd, getCollapseNumberExpr(Clauses), + /*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack, + VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp for loop exprs were not built"); + + if (!CurContext->isDependentContext()) { + // Finalize the clauses that need pre-built expressions for CodeGen. + for (OMPClause *C : Clauses) { + if (auto *LC = dyn_cast<OMPLinearClause>(C)) + if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), + B.NumIterations, *this, CurScope, + DSAStack)) + return StmtError(); + } + } + + // OpenMP, [2.9.2 taskloop Construct, Restrictions] + // The grainsize clause and num_tasks clause are mutually exclusive and may + // not appear on the same taskloop directive. + if (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 OMPMasterTaskLoopSimdDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopDirective( + 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); + 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, getCollapseNumberExpr(Clauses), + /*OrderedLoopCountExpr=*/nullptr, CS, *this, *DSAStack, + VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp for loop exprs were not built"); + + // OpenMP, [2.9.2 taskloop Construct, Restrictions] + // The grainsize clause and num_tasks clause are mutually exclusive and may + // not appear on the same taskloop directive. + if (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(); + + setFunctionHasBranchProtectedScope(); + return OMPParallelMasterTaskLoopDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); +} + StmtResult Sema::ActOnOpenMPDistributeDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { @@ -9246,6 +10315,8 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_atomic_default_mem_order: + case OMPC_device_type: + case OMPC_match: llvm_unreachable("Clause is not allowed."); } return Res; @@ -9287,6 +10358,10 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_target_exit_data: CaptureRegion = OMPD_task; break; + case OMPD_parallel_master_taskloop: + if (NameModifier == OMPD_unknown || NameModifier == OMPD_taskloop) + CaptureRegion = OMPD_parallel; + break; case OMPD_cancel: case OMPD_parallel: case OMPD_parallel_sections: @@ -9302,6 +10377,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_task: case OMPD_taskloop: case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: case OMPD_target_data: // Do not capture if-clause expressions. break; @@ -9315,6 +10392,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_teams: @@ -9358,6 +10436,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_parallel_for_simd: case OMPD_distribute_parallel_for: case OMPD_distribute_parallel_for_simd: + case OMPD_parallel_master_taskloop: // Do not capture num_threads-clause expressions. break; case OMPD_target_data: @@ -9373,6 +10452,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_task: case OMPD_taskloop: case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: case OMPD_threadprivate: case OMPD_allocate: case OMPD_taskyield: @@ -9383,6 +10464,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_teams: @@ -9428,6 +10510,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_task: case OMPD_taskloop: case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: + case OMPD_parallel_master_taskloop: case OMPD_target_data: case OMPD_target_enter_data: case OMPD_target_exit_data: @@ -9452,6 +10537,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -9494,6 +10580,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_task: case OMPD_taskloop: case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: + case OMPD_parallel_master_taskloop: case OMPD_target_data: case OMPD_target_enter_data: case OMPD_target_exit_data: @@ -9518,6 +10607,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -9560,6 +10650,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_task: case OMPD_taskloop: case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: + case OMPD_parallel_master_taskloop: case OMPD_target_data: case OMPD_target_enter_data: case OMPD_target_exit_data: @@ -9585,6 +10678,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -9630,6 +10724,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_task: case OMPD_taskloop: case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: + case OMPD_parallel_master_taskloop: case OMPD_target_data: case OMPD_target_enter_data: case OMPD_target_exit_data: @@ -9651,6 +10748,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -9701,6 +10799,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_task: case OMPD_taskloop: case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: + case OMPD_parallel_master_taskloop: case OMPD_cancel: case OMPD_parallel: case OMPD_parallel_sections: @@ -9716,6 +10817,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -9737,6 +10839,78 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( llvm_unreachable("Unknown OpenMP directive"); } break; + case OMPC_grainsize: + case OMPC_num_tasks: + case OMPC_final: + case OMPC_priority: + switch (DKind) { + case OMPD_task: + case OMPD_taskloop: + case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: + break; + case OMPD_parallel_master_taskloop: + CaptureRegion = OMPD_parallel; + break; + case OMPD_target_update: + case OMPD_target_enter_data: + case OMPD_target_exit_data: + case OMPD_target: + case OMPD_target_simd: + case OMPD_target_teams: + case OMPD_target_parallel: + case OMPD_target_teams_distribute: + case OMPD_target_teams_distribute_simd: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: + case OMPD_target_teams_distribute_parallel_for: + case OMPD_target_teams_distribute_parallel_for_simd: + case OMPD_target_data: + case OMPD_teams_distribute_parallel_for: + case OMPD_teams_distribute_parallel_for_simd: + case OMPD_teams: + case OMPD_teams_distribute: + case OMPD_teams_distribute_simd: + case OMPD_distribute_parallel_for: + case OMPD_distribute_parallel_for_simd: + case OMPD_cancel: + case OMPD_parallel: + case OMPD_parallel_sections: + case OMPD_parallel_for: + case OMPD_parallel_for_simd: + case OMPD_threadprivate: + case OMPD_allocate: + case OMPD_taskyield: + case OMPD_barrier: + case OMPD_taskwait: + case OMPD_cancellation_point: + case OMPD_flush: + case OMPD_declare_reduction: + case OMPD_declare_mapper: + case OMPD_declare_simd: + case OMPD_declare_variant: + case OMPD_declare_target: + case OMPD_end_declare_target: + case OMPD_simd: + case OMPD_for: + case OMPD_for_simd: + case OMPD_sections: + case OMPD_section: + case OMPD_single: + case OMPD_master: + case OMPD_critical: + case OMPD_taskgroup: + case OMPD_distribute: + case OMPD_ordered: + case OMPD_atomic: + case OMPD_distribute_simd: + case OMPD_requires: + llvm_unreachable("Unexpected OpenMP directive with grainsize-clause"); + case OMPD_unknown: + llvm_unreachable("Unknown OpenMP directive"); + } + break; case OMPC_firstprivate: case OMPC_lastprivate: case OMPC_reduction: @@ -9745,7 +10919,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_linear: case OMPC_default: case OMPC_proc_bind: - case OMPC_final: case OMPC_safelen: case OMPC_simdlen: case OMPC_allocator: @@ -9771,10 +10944,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_threads: case OMPC_simd: case OMPC_map: - case OMPC_priority: - case OMPC_grainsize: case OMPC_nogroup: - case OMPC_num_tasks: case OMPC_hint: case OMPC_defaultmap: case OMPC_unknown: @@ -9788,6 +10958,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_atomic_default_mem_order: + case OMPC_device_type: + case OMPC_match: llvm_unreachable("Unexpected OpenMP clause."); } return CaptureRegion; @@ -9832,6 +11004,8 @@ OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = Condition; + Stmt *HelperValStmt = nullptr; + OpenMPDirectiveKind CaptureRegion = OMPD_unknown; if (!Condition->isValueDependent() && !Condition->isTypeDependent() && !Condition->isInstantiationDependent() && !Condition->containsUnexpandedParameterPack()) { @@ -9840,10 +11014,21 @@ OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition, return nullptr; ValExpr = MakeFullExpr(Val.get()).get(); + + OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); + CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_final); + if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { + ValExpr = MakeFullExpr(ValExpr).get(); + llvm::MapVector<const Expr *, DeclRefExpr *> Captures; + ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); + HelperValStmt = buildPreInits(Context, Captures); + } } - return new (Context) OMPFinalClause(ValExpr, StartLoc, LParenLoc, EndLoc); + return new (Context) OMPFinalClause(ValExpr, HelperValStmt, CaptureRegion, + StartLoc, LParenLoc, EndLoc); } + ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc, Expr *Op) { if (!Op) @@ -9888,9 +11073,12 @@ ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc, return PerformContextualImplicitConversion(Loc, Op, ConvertDiagnoser); } -static bool isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, - OpenMPClauseKind CKind, - bool StrictlyPositive) { +static bool +isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, OpenMPClauseKind CKind, + bool StrictlyPositive, bool BuildCapture = false, + OpenMPDirectiveKind DKind = OMPD_unknown, + OpenMPDirectiveKind *CaptureRegion = nullptr, + Stmt **HelperValStmt = nullptr) { if (!ValExpr->isTypeDependent() && !ValExpr->isValueDependent() && !ValExpr->isInstantiationDependent()) { SourceLocation Loc = ValExpr->getExprLoc(); @@ -9911,6 +11099,16 @@ static bool isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, << ValExpr->getSourceRange(); return false; } + if (!BuildCapture) + return true; + *CaptureRegion = getOpenMPCaptureRegionForClause(DKind, CKind); + if (*CaptureRegion != OMPD_unknown && + !SemaRef.CurContext->isDependentContext()) { + ValExpr = SemaRef.MakeFullExpr(ValExpr).get(); + llvm::MapVector<const Expr *, DeclRefExpr *> Captures; + ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get(); + *HelperValStmt = buildPreInits(SemaRef.Context, Captures); + } } return true; } @@ -10181,6 +11379,8 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_unified_shared_memory: case OMPC_reverse_offload: case OMPC_dynamic_allocators: + case OMPC_device_type: + case OMPC_match: llvm_unreachable("Clause is not allowed."); } return Res; @@ -10359,6 +11559,8 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_atomic_default_mem_order: + case OMPC_device_type: + case OMPC_match: llvm_unreachable("Clause is not allowed."); } return Res; @@ -10568,6 +11770,8 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_use_device_ptr: case OMPC_is_device_ptr: case OMPC_atomic_default_mem_order: + case OMPC_device_type: + case OMPC_match: llvm_unreachable("Clause is not allowed."); } return Res; @@ -10774,6 +11978,8 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_atomic_default_mem_order: + case OMPC_device_type: + case OMPC_match: llvm_unreachable("Clause is not allowed."); } return Res; @@ -10874,7 +12080,13 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, // OpenMP 4.5 [2.15.5.1, Restrictions, p.3] // A list item cannot appear in both a map clause and a data-sharing // attribute clause on the same construct - if (isOpenMPTargetExecutionDirective(CurrDir)) { + // + // OpenMP 5.0 [2.19.7.1, Restrictions, p.7] + // A list item cannot appear in both a map clause and a data-sharing + // attribute clause on the same construct unless the construct is a + // combined construct. + if ((LangOpts.OpenMP <= 45 && isOpenMPTargetExecutionDirective(CurrDir)) || + CurrDir == OMPD_target) { OpenMPClauseKind ConflictKind; if (DSAStack->checkMappableExprComponentListsForDecl( VD, /*CurrentRegionOnly=*/true, @@ -11109,7 +12321,14 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // OpenMP 4.5 [2.15.5.1, Restrictions, p.3] // A list item cannot appear in both a map clause and a data-sharing // attribute clause on the same construct - if (isOpenMPTargetExecutionDirective(CurrDir)) { + // + // OpenMP 5.0 [2.19.7.1, Restrictions, p.7] + // A list item cannot appear in both a map clause and a data-sharing + // attribute clause on the same construct unless the construct is a + // combined construct. + if ((LangOpts.OpenMP <= 45 && + isOpenMPTargetExecutionDirective(CurrDir)) || + CurrDir == OMPD_target) { OpenMPClauseKind ConflictKind; if (DSAStack->checkMappableExprComponentListsForDecl( VD, /*CurrentRegionOnly=*/true, @@ -12133,8 +13352,9 @@ static bool actOnOMPReductionKindClause( // If we don't have a single element, we must emit a constant array type. if (ConstantLengthOASE && !SingleElement) { for (llvm::APSInt &Size : ArraySizes) - PrivateTy = Context.getConstantArrayType( - PrivateTy, Size, ArrayType::Normal, /*IndexTypeQuals=*/0); + PrivateTy = Context.getConstantArrayType(PrivateTy, Size, nullptr, + ArrayType::Normal, + /*IndexTypeQuals=*/0); } } @@ -12707,6 +13927,7 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, // Walk the vars and build update/final expressions for the CodeGen. SmallVector<Expr *, 8> Updates; SmallVector<Expr *, 8> Finals; + SmallVector<Expr *, 8> UsedExprs; Expr *Step = Clause.getStep(); Expr *CalcStep = Clause.getCalcStep(); // OpenMP [2.14.3.7, linear clause] @@ -12760,9 +13981,9 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, // Build update: Var = InitExpr + IV * Step ExprResult Update; if (!Info.first) - Update = - buildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, - InitExpr, IV, Step, /* Subtract */ false); + Update = buildCounterUpdate( + SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, InitExpr, IV, Step, + /*Subtract=*/false, /*IsNonRectangularLB=*/false); else Update = *CurPrivate; Update = SemaRef.ActOnFinishFullExpr(Update.get(), DE->getBeginLoc(), @@ -12773,7 +13994,8 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, if (!Info.first) Final = buildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef, - InitExpr, NumIterations, Step, /*Subtract=*/false); + InitExpr, NumIterations, Step, /*Subtract=*/false, + /*IsNonRectangularLB=*/false); else Final = *CurPrivate; Final = SemaRef.ActOnFinishFullExpr(Final.get(), DE->getBeginLoc(), @@ -12782,16 +14004,24 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, if (!Update.isUsable() || !Final.isUsable()) { Updates.push_back(nullptr); Finals.push_back(nullptr); + UsedExprs.push_back(nullptr); HasErrors = true; } else { Updates.push_back(Update.get()); Finals.push_back(Final.get()); + if (!Info.first) + UsedExprs.push_back(SimpleRefExpr); } ++CurInit; ++CurPrivate; } + if (Expr *S = Clause.getStep()) + UsedExprs.push_back(S); + // Fill the remaining part with the nullptr. + UsedExprs.append(Clause.varlist_size() + 1 - UsedExprs.size(), nullptr); Clause.setUpdates(Updates); Clause.setFinals(Finals); + Clause.setUsedExprs(UsedExprs); return HasErrors; } @@ -13216,11 +14446,13 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, << RefExpr->getSourceRange(); continue; } - bool Suppress = getDiagnostics().getSuppressAllDiagnostics(); - getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true); - ExprResult Res = - CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RefExpr->IgnoreParenImpCasts()); - getDiagnostics().setSuppressAllDiagnostics(Suppress); + + ExprResult Res; + { + Sema::TentativeAnalysisScope Trap(*this); + Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, + RefExpr->IgnoreParenImpCasts()); + } if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr)) { Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) << RefExpr->getSourceRange(); @@ -13884,6 +15116,11 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S, Expr *UnresolvedMapper) { if (MapperIdScopeSpec.isInvalid()) return ExprError(); + // Get the actual type for the array type. + if (Type->isArrayType()) { + assert(Type->getAsArrayTypeUnsafe() && "Expect to get a valid array type"); + Type = Type->getAsArrayTypeUnsafe()->getElementType().getCanonicalType(); + } // Find all user-defined mappers with the given MapperId. SmallVector<UnresolvedSet<8>, 4> Lookups; LookupResult Lookup(SemaRef, MapperId, Sema::LookupOMPMapperName); @@ -13930,11 +15167,14 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S, MapperIdScopeSpec.getWithLocInContext(SemaRef.Context), MapperId, /*ADL=*/false, /*Overloaded=*/true, URS.begin(), URS.end()); } + SourceLocation Loc = MapperId.getLoc(); // [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions // The type must be of struct, union or class type in C and C++ - if (!Type->isStructureOrClassType() && !Type->isUnionType()) - return ExprEmpty(); - SourceLocation Loc = MapperId.getLoc(); + if (!Type->isStructureOrClassType() && !Type->isUnionType() && + (MapperIdScopeSpec.isSet() || MapperId.getAsString() != "default")) { + SemaRef.Diag(Loc, diag::err_omp_mapper_wrong_type); + return ExprError(); + } // Perform argument dependent lookup. if (SemaRef.getLangOpts().CPlusPlus && !MapperIdScopeSpec.isSet()) argumentDependentLookup(SemaRef, MapperId, Loc, Type, Lookups); @@ -14211,7 +15451,14 @@ static void checkMappableExpressionList( // OpenMP 4.5 [2.15.5.1, Restrictions, p.3] // A list item cannot appear in both a map clause and a data-sharing // attribute clause on the same construct - if (VD && isOpenMPTargetExecutionDirective(DKind)) { + // + // OpenMP 5.0 [2.19.7.1, Restrictions, p.7] + // A list item cannot appear in both a map clause and a data-sharing + // attribute clause on the same construct unless the construct is a + // combined construct. + if (VD && ((SemaRef.LangOpts.OpenMP <= 45 && + isOpenMPTargetExecutionDirective(DKind)) || + DKind == OMPD_target)) { DSAStackTy::DSAVarData DVar = DSAS->getTopDSA(VD, /*FromParent=*/false); if (isOpenMPPrivate(DVar.CKind)) { SemaRef.Diag(ELoc, diag::err_omp_variable_in_given_clause_and_dsa) @@ -14745,14 +15992,19 @@ OMPClause *Sema::ActOnOpenMPPriorityClause(Expr *Priority, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = Priority; + Stmt *HelperValStmt = nullptr; + OpenMPDirectiveKind CaptureRegion = OMPD_unknown; // OpenMP [2.9.1, task Constrcut] // The priority-value is a non-negative numerical scalar expression. - if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_priority, - /*StrictlyPositive=*/false)) + if (!isNonNegativeIntegerValue( + ValExpr, *this, OMPC_priority, + /*StrictlyPositive=*/false, /*BuildCapture=*/true, + DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt)) return nullptr; - return new (Context) OMPPriorityClause(ValExpr, StartLoc, LParenLoc, EndLoc); + return new (Context) OMPPriorityClause(ValExpr, HelperValStmt, CaptureRegion, + StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize, @@ -14760,15 +16012,20 @@ OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = Grainsize; + Stmt *HelperValStmt = nullptr; + OpenMPDirectiveKind CaptureRegion = OMPD_unknown; // OpenMP [2.9.2, taskloop Constrcut] // The parameter of the grainsize clause must be a positive integer // expression. - if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_grainsize, - /*StrictlyPositive=*/true)) + if (!isNonNegativeIntegerValue( + ValExpr, *this, OMPC_grainsize, + /*StrictlyPositive=*/true, /*BuildCapture=*/true, + DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt)) return nullptr; - return new (Context) OMPGrainsizeClause(ValExpr, StartLoc, LParenLoc, EndLoc); + return new (Context) OMPGrainsizeClause(ValExpr, HelperValStmt, CaptureRegion, + StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks, @@ -14776,15 +16033,20 @@ OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks, SourceLocation LParenLoc, SourceLocation EndLoc) { Expr *ValExpr = NumTasks; + Stmt *HelperValStmt = nullptr; + OpenMPDirectiveKind CaptureRegion = OMPD_unknown; // OpenMP [2.9.2, taskloop Constrcut] // The parameter of the num_tasks clause must be a positive integer // expression. - if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_num_tasks, - /*StrictlyPositive=*/true)) + if (!isNonNegativeIntegerValue( + ValExpr, *this, OMPC_num_tasks, + /*StrictlyPositive=*/true, /*BuildCapture=*/true, + DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt)) return nullptr; - return new (Context) OMPNumTasksClause(ValExpr, StartLoc, LParenLoc, EndLoc); + return new (Context) OMPNumTasksClause(ValExpr, HelperValStmt, CaptureRegion, + StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc, @@ -14905,16 +16167,15 @@ void Sema::ActOnFinishOpenMPDeclareTargetDirective() { --DeclareTargetNestingLevel; } -void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope, - CXXScopeSpec &ScopeSpec, - const DeclarationNameInfo &Id, - OMPDeclareTargetDeclAttr::MapTypeTy MT, - NamedDeclSetType &SameDirectiveDecls) { +NamedDecl * +Sema::lookupOpenMPDeclareTargetName(Scope *CurScope, CXXScopeSpec &ScopeSpec, + const DeclarationNameInfo &Id, + NamedDeclSetType &SameDirectiveDecls) { LookupResult Lookup(*this, Id, LookupOrdinaryName); LookupParsedName(Lookup, CurScope, &ScopeSpec, true); if (Lookup.isAmbiguous()) - return; + return nullptr; Lookup.suppressDiagnostics(); if (!Lookup.isSingleResult()) { @@ -14925,33 +16186,56 @@ void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope, diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest) << Id.getName()); checkDeclIsAllowedInOpenMPTarget(nullptr, Corrected.getCorrectionDecl()); - return; + return nullptr; } Diag(Id.getLoc(), diag::err_undeclared_var_use) << Id.getName(); - return; + return nullptr; } NamedDecl *ND = Lookup.getAsSingle<NamedDecl>(); - if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND) || - isa<FunctionTemplateDecl>(ND)) { - if (!SameDirectiveDecls.insert(cast<NamedDecl>(ND->getCanonicalDecl()))) - Diag(Id.getLoc(), diag::err_omp_declare_target_multiple) << Id.getName(); - llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = - OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration( - cast<ValueDecl>(ND)); - if (!Res) { - auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT); - ND->addAttr(A); - if (ASTMutationListener *ML = Context.getASTMutationListener()) - ML->DeclarationMarkedOpenMPDeclareTarget(ND, A); - checkDeclIsAllowedInOpenMPTarget(nullptr, ND, Id.getLoc()); - } else if (*Res != MT) { - Diag(Id.getLoc(), diag::err_omp_declare_target_to_and_link) - << Id.getName(); - } - } else { + if (!isa<VarDecl>(ND) && !isa<FunctionDecl>(ND) && + !isa<FunctionTemplateDecl>(ND)) { Diag(Id.getLoc(), diag::err_omp_invalid_target_decl) << Id.getName(); + return nullptr; + } + if (!SameDirectiveDecls.insert(cast<NamedDecl>(ND->getCanonicalDecl()))) + Diag(Id.getLoc(), diag::err_omp_declare_target_multiple) << Id.getName(); + return ND; +} + +void Sema::ActOnOpenMPDeclareTargetName( + NamedDecl *ND, SourceLocation Loc, OMPDeclareTargetDeclAttr::MapTypeTy MT, + OMPDeclareTargetDeclAttr::DevTypeTy DT) { + assert((isa<VarDecl>(ND) || isa<FunctionDecl>(ND) || + isa<FunctionTemplateDecl>(ND)) && + "Expected variable, function or function template."); + + // Diagnose marking after use as it may lead to incorrect diagnosis and + // codegen. + if (LangOpts.OpenMP >= 50 && + (ND->isUsed(/*CheckUsedAttr=*/false) || ND->isReferenced())) + Diag(Loc, diag::warn_omp_declare_target_after_first_use); + + Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + OMPDeclareTargetDeclAttr::getDeviceType(cast<ValueDecl>(ND)); + if (DevTy.hasValue() && *DevTy != DT) { + Diag(Loc, diag::err_omp_device_type_mismatch) + << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(DT) + << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(*DevTy); + return; + } + Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = + OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(cast<ValueDecl>(ND)); + if (!Res) { + auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT, DT, + SourceRange(Loc, Loc)); + ND->addAttr(A); + if (ASTMutationListener *ML = Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(ND, A); + checkDeclIsAllowedInOpenMPTarget(nullptr, ND, Loc); + } else if (*Res != MT) { + Diag(Loc, diag::err_omp_declare_target_to_and_link) << ND; } } @@ -14960,7 +16244,28 @@ static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR, if (!D || !isa<VarDecl>(D)) return; auto *VD = cast<VarDecl>(D); - if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) + Optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapTy = + OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD); + if (SemaRef.LangOpts.OpenMP >= 50 && + (SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true) || + SemaRef.getCurBlock() || SemaRef.getCurCapturedRegion()) && + VD->hasGlobalStorage()) { + llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapTy = + OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD); + if (!MapTy || *MapTy != OMPDeclareTargetDeclAttr::MT_To) { + // OpenMP 5.0, 2.12.7 declare target Directive, Restrictions + // If a lambda declaration and definition appears between a + // declare target directive and the matching end declare target + // directive, all variables that are captured by the lambda + // expression must also appear in a to clause. + SemaRef.Diag(VD->getLocation(), + diag::err_omp_lambda_capture_in_declare_target_not_to); + SemaRef.Diag(SL, diag::note_var_explicitly_captured_here) + << VD << 0 << SR; + return; + } + } + if (MapTy.hasValue()) return; SemaRef.Diag(VD->getLocation(), diag::warn_omp_not_in_target_context); SemaRef.Diag(SL, diag::note_used_here) << SR; @@ -14969,7 +16274,7 @@ static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR, static bool checkValueDeclInTarget(SourceLocation SL, SourceRange SR, Sema &SemaRef, DSAStackTy *Stack, ValueDecl *VD) { - return VD->hasAttr<OMPDeclareTargetDeclAttr>() || + return OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD) || checkTypeMappable(SL, SR, SemaRef, Stack, VD->getType(), /*FullCheck=*/false); } @@ -14995,15 +16300,23 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, } if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D)) D = FTD->getTemplatedDecl(); - if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + if (auto *FD = dyn_cast<FunctionDecl>(D)) { llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(FD); - if (Res && *Res == OMPDeclareTargetDeclAttr::MT_Link) { - assert(IdLoc.isValid() && "Source location is expected"); + if (IdLoc.isValid() && Res && *Res == OMPDeclareTargetDeclAttr::MT_Link) { Diag(IdLoc, diag::err_omp_function_in_link_clause); Diag(FD->getLocation(), diag::note_defined_here) << FD; return; } + // Mark the function as must be emitted for the device. + Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + OMPDeclareTargetDeclAttr::getDeviceType(FD); + if (LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid() && + *DevTy != OMPDeclareTargetDeclAttr::DT_Host) + checkOpenMPDeviceFunction(IdLoc, FD, /*CheckForDelayedContext=*/false); + if (!LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid() && + *DevTy != OMPDeclareTargetDeclAttr::DT_NoHost) + checkOpenMPHostFunction(IdLoc, FD, /*CheckCaller=*/false); } if (auto *VD = dyn_cast<ValueDecl>(D)) { // Problem if any with var declared with incomplete type will be reported @@ -15016,7 +16329,8 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, if (isa<VarDecl>(D) || isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) { auto *A = OMPDeclareTargetDeclAttr::CreateImplicit( - Context, OMPDeclareTargetDeclAttr::MT_To); + Context, OMPDeclareTargetDeclAttr::MT_To, + OMPDeclareTargetDeclAttr::DT_Any, SourceRange(IdLoc, IdLoc)); D->addAttr(A); if (ASTMutationListener *ML = Context.getASTMutationListener()) ML->DeclarationMarkedOpenMPDeclareTarget(D, A); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index f632a4d3bd1a..47c1e3cec0ea 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -257,8 +257,18 @@ isPointerConversionToVoidPointer(ASTContext& Context) const { /// Skip any implicit casts which could be either part of a narrowing conversion /// or after one in an implicit conversion. -static const Expr *IgnoreNarrowingConversion(const Expr *Converted) { - while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Converted)) { +static const Expr *IgnoreNarrowingConversion(ASTContext &Ctx, + const Expr *Converted) { + // We can have cleanups wrapping the converted expression; these need to be + // preserved so that destructors run if necessary. + if (auto *EWC = dyn_cast<ExprWithCleanups>(Converted)) { + Expr *Inner = + const_cast<Expr *>(IgnoreNarrowingConversion(Ctx, EWC->getSubExpr())); + return ExprWithCleanups::Create(Ctx, Inner, EWC->cleanupsHaveSideEffects(), + EWC->getObjects()); + } + + while (auto *ICE = dyn_cast<ImplicitCastExpr>(Converted)) { switch (ICE->getCastKind()) { case CK_NoOp: case CK_IntegralCast: @@ -332,7 +342,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind( if (IgnoreFloatToIntegralConversion) return NK_Not_Narrowing; llvm::APSInt IntConstantValue; - const Expr *Initializer = IgnoreNarrowingConversion(Converted); + const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted); assert(Initializer && "Unknown conversion expression"); // If it's value-dependent, we can't tell whether it's narrowing. @@ -370,7 +380,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind( if (FromType->isRealFloatingType() && ToType->isRealFloatingType() && Ctx.getFloatingTypeOrder(FromType, ToType) == 1) { // FromType is larger than ToType. - const Expr *Initializer = IgnoreNarrowingConversion(Converted); + const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted); // If it's value-dependent, we can't tell whether it's narrowing. if (Initializer->isValueDependent()) @@ -416,7 +426,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind( (FromSigned && !ToSigned)) { // Not all values of FromType can be represented in ToType. llvm::APSInt InitializerValue; - const Expr *Initializer = IgnoreNarrowingConversion(Converted); + const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted); // If it's value-dependent, we can't tell whether it's narrowing. if (Initializer->isValueDependent()) @@ -838,6 +848,25 @@ llvm::Optional<unsigned> DeductionFailureInfo::getCallArgIndex() { } } +bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed( + OverloadedOperatorKind Op) { + if (!AllowRewrittenCandidates) + return false; + return Op == OO_EqualEqual || Op == OO_Spaceship; +} + +bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed( + ASTContext &Ctx, const FunctionDecl *FD) { + if (!shouldAddReversed(FD->getDeclName().getCXXOverloadedOperator())) + return false; + // Don't bother adding a reversed candidate that can never be a better + // match than the non-reversed version. + return FD->getNumParams() != 2 || + !Ctx.hasSameUnqualifiedType(FD->getParamDecl(0)->getType(), + FD->getParamDecl(1)->getType()) || + FD->hasAttr<EnableIfAttr>(); +} + void OverloadCandidateSet::destroyCandidates() { for (iterator i = begin(), e = end(); i != e; ++i) { for (auto &C : i->Conversions) @@ -1463,14 +1492,14 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType, if (TyClass != CanFrom->getTypeClass()) return false; if (TyClass != Type::FunctionProto && TyClass != Type::FunctionNoProto) { if (TyClass == Type::Pointer) { - CanTo = CanTo.getAs<PointerType>()->getPointeeType(); - CanFrom = CanFrom.getAs<PointerType>()->getPointeeType(); + CanTo = CanTo.castAs<PointerType>()->getPointeeType(); + CanFrom = CanFrom.castAs<PointerType>()->getPointeeType(); } else if (TyClass == Type::BlockPointer) { - CanTo = CanTo.getAs<BlockPointerType>()->getPointeeType(); - CanFrom = CanFrom.getAs<BlockPointerType>()->getPointeeType(); + CanTo = CanTo.castAs<BlockPointerType>()->getPointeeType(); + CanFrom = CanFrom.castAs<BlockPointerType>()->getPointeeType(); } else if (TyClass == Type::MemberPointer) { - auto ToMPT = CanTo.getAs<MemberPointerType>(); - auto FromMPT = CanFrom.getAs<MemberPointerType>(); + auto ToMPT = CanTo.castAs<MemberPointerType>(); + auto FromMPT = CanFrom.castAs<MemberPointerType>(); // A function pointer conversion cannot change the class of the function. if (ToMPT->getClass() != FromMPT->getClass()) return false; @@ -2273,7 +2302,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, // Blocks: Block pointers can be converted to void*. if (FromType->isBlockPointerType() && ToType->isPointerType() && - ToType->getAs<PointerType>()->getPointeeType()->isVoidType()) { + ToType->castAs<PointerType>()->getPointeeType()->isVoidType()) { ConvertedType = ToType; return true; } @@ -3272,7 +3301,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType, User.ConversionFunction = Constructor; User.FoundConversionFunction = Best->FoundDecl; User.After.setAsIdentityConversion(); - User.After.setFromType(ThisType->getAs<PointerType>()->getPointeeType()); + User.After.setFromType(ThisType->castAs<PointerType>()->getPointeeType()); User.After.setAllToTypes(ToType); return Result; } @@ -3463,7 +3492,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, User.ConversionFunction = Constructor; User.FoundConversionFunction = Best->FoundDecl; User.After.setAsIdentityConversion(); - User.After.setFromType(ThisType->getAs<PointerType>()->getPointeeType()); + User.After.setFromType(ThisType->castAs<PointerType>()->getPointeeType()); User.After.setAllToTypes(ToType); return Result; } @@ -3755,6 +3784,34 @@ isBetterReferenceBindingKind(const StandardConversionSequence &SCS1, !SCS2.IsLvalueReference && SCS2.BindsToFunctionLvalue); } +enum class FixedEnumPromotion { + None, + ToUnderlyingType, + ToPromotedUnderlyingType +}; + +/// Returns kind of fixed enum promotion the \a SCS uses. +static FixedEnumPromotion +getFixedEnumPromtion(Sema &S, const StandardConversionSequence &SCS) { + + if (SCS.Second != ICK_Integral_Promotion) + return FixedEnumPromotion::None; + + QualType FromType = SCS.getFromType(); + if (!FromType->isEnumeralType()) + return FixedEnumPromotion::None; + + EnumDecl *Enum = FromType->getAs<EnumType>()->getDecl(); + if (!Enum->isFixed()) + return FixedEnumPromotion::None; + + QualType UnderlyingType = Enum->getIntegerType(); + if (S.Context.hasSameType(SCS.getToType(1), UnderlyingType)) + return FixedEnumPromotion::ToUnderlyingType; + + return FixedEnumPromotion::ToPromotedUnderlyingType; +} + /// CompareStandardConversionSequences - Compare two standard /// conversion sequences to determine whether one is better than the /// other or if they are indistinguishable (C++ 13.3.3.2p3). @@ -3796,6 +3853,20 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc, ? ImplicitConversionSequence::Better : ImplicitConversionSequence::Worse; + // C++14 [over.ics.rank]p4b2: + // This is retroactively applied to C++11 by CWG 1601. + // + // A conversion that promotes an enumeration whose underlying type is fixed + // to its underlying type is better than one that promotes to the promoted + // underlying type, if the two are different. + FixedEnumPromotion FEP1 = getFixedEnumPromtion(S, SCS1); + FixedEnumPromotion FEP2 = getFixedEnumPromtion(S, SCS2); + if (FEP1 != FixedEnumPromotion::None && FEP2 != FixedEnumPromotion::None && + FEP1 != FEP2) + return FEP1 == FixedEnumPromotion::ToUnderlyingType + ? ImplicitConversionSequence::Better + : ImplicitConversionSequence::Worse; + // C++ [over.ics.rank]p4b2: // // If class B is derived directly or indirectly from class A, @@ -4105,14 +4176,14 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc, /*FIXME: Remove if Objective-C id conversions get their own rank*/ FromType1->isPointerType() && FromType2->isPointerType() && ToType1->isPointerType() && ToType2->isPointerType()) { - QualType FromPointee1 - = FromType1->getAs<PointerType>()->getPointeeType().getUnqualifiedType(); - QualType ToPointee1 - = ToType1->getAs<PointerType>()->getPointeeType().getUnqualifiedType(); - QualType FromPointee2 - = FromType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType(); - QualType ToPointee2 - = ToType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType(); + QualType FromPointee1 = + FromType1->castAs<PointerType>()->getPointeeType().getUnqualifiedType(); + QualType ToPointee1 = + ToType1->castAs<PointerType>()->getPointeeType().getUnqualifiedType(); + QualType FromPointee2 = + FromType2->castAs<PointerType>()->getPointeeType().getUnqualifiedType(); + QualType ToPointee2 = + ToType2->castAs<PointerType>()->getPointeeType().getUnqualifiedType(); // -- conversion of C* to B* is better than conversion of C* to A*, if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) { @@ -4301,7 +4372,8 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, QualType OrigT1, QualType OrigT2, bool &DerivedToBase, bool &ObjCConversion, - bool &ObjCLifetimeConversion) { + bool &ObjCLifetimeConversion, + bool &FunctionConversion) { assert(!OrigT1->isReferenceType() && "T1 must be the pointee type of the reference type"); assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type"); @@ -4331,15 +4403,16 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, Context.canBindObjCObjectType(UnqualT1, UnqualT2)) ObjCConversion = true; else if (UnqualT2->isFunctionType() && - IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2)) + 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; return Ref_Compatible; - else + } else return Ref_Incompatible; // At this point, we know that T1 and T2 are reference-related (at @@ -4392,7 +4465,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, bool AllowExplicit) { assert(T2->isRecordType() && "Can only find conversions of record types."); CXXRecordDecl *T2RecordDecl - = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl()); + = dyn_cast<CXXRecordDecl>(T2->castAs<RecordType>()->getDecl()); OverloadCandidateSet CandidateSet( DeclLoc, OverloadCandidateSet::CSK_InitByUserDefinedConversion); @@ -4420,6 +4493,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, 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. @@ -4432,12 +4506,13 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, if (!ConvTemplate && S.CompareReferenceRelationship( - DeclLoc, - Conv->getConversionType().getNonReferenceType() - .getUnqualifiedType(), - DeclType.getNonReferenceType().getUnqualifiedType(), - DerivedToBase, ObjCConversion, ObjCLifetimeConversion) == - Sema::Ref_Incompatible) + DeclLoc, + Conv->getConversionType() + .getNonReferenceType() + .getUnqualifiedType(), + DeclType.getNonReferenceType().getUnqualifiedType(), + DerivedToBase, ObjCConversion, ObjCLifetimeConversion, + FunctionConversion) == Sema::Ref_Incompatible) continue; } else { // If the conversion function doesn't return a reference type, @@ -4523,7 +4598,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, ImplicitConversionSequence ICS; ICS.setBad(BadConversionSequence::no_conversion, Init, DeclType); - QualType T1 = DeclType->getAs<ReferenceType>()->getPointeeType(); + QualType T1 = DeclType->castAs<ReferenceType>()->getPointeeType(); QualType T2 = Init->getType(); // If the initializer is the address of an overloaded function, try @@ -4541,11 +4616,11 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, 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); - + Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship( + DeclLoc, T1, T2, DerivedToBase, ObjCConversion, ObjCLifetimeConversion, + FunctionConversion); // C++0x [dcl.init.ref]p5: // A reference to type "cv1 T1" is initialized by an expression @@ -4920,13 +4995,11 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, // Type is an aggregate, argument is an init list. At this point it comes // down to checking whether the initialization works. // FIXME: Find out whether this parameter is consumed or not. - // FIXME: Expose SemaInit's aggregate initialization code so that we don't - // need to call into the initialization code here; overload resolution - // should not be doing that. InitializedEntity Entity = InitializedEntity::InitializeParameter(S.Context, ToType, /*Consumed=*/false); - if (S.CanPerformCopyInitialization(Entity, From)) { + if (S.CanPerformAggregateInitializationForOverloadResolution(Entity, + From)) { Result.setUserDefined(); Result.UserDefined.Before.setAsIdentityConversion(); // Initializer lists don't have a type. @@ -4949,7 +5022,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, // mention initializer lists in any way. So we go by what list- // initialization would do and try to extrapolate from that. - QualType T1 = ToType->getAs<ReferenceType>()->getPointeeType(); + QualType T1 = ToType->castAs<ReferenceType>()->getPointeeType(); // If the initializer list has a single element that is reference-related // to the parameter type, we initialize the reference from that. @@ -4972,9 +5045,10 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, bool dummy1 = false; bool dummy2 = false; bool dummy3 = false; + bool dummy4 = false; Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(From->getBeginLoc(), T1, T2, dummy1, - dummy2, dummy3); + dummy2, dummy3, dummy4); if (RefRelationship >= Sema::Ref_Related) { return TryReferenceInit(S, Init, ToType, /*FIXME*/ From->getBeginLoc(), @@ -5219,7 +5293,7 @@ Sema::PerformObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) { QualType FromRecordType, DestType; QualType ImplicitParamRecordType = - Method->getThisType()->getAs<PointerType>()->getPointeeType(); + Method->getThisType()->castAs<PointerType>()->getPointeeType(); Expr::Classification FromClassification; if (const PointerType *PT = From->getType()->getAs<PointerType>()) { @@ -5467,6 +5541,14 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, if (Result.isInvalid()) return Result; + // C++2a [intro.execution]p5: + // A full-expression is [...] a constant-expression [...] + Result = + S.ActOnFinishFullExpr(Result.get(), From->getExprLoc(), + /*DiscardedValue=*/false, /*IsConstexpr=*/true); + if (Result.isInvalid()) + return Result; + // Check for a narrowing implicit conversion. APValue PreNarrowingValue; QualType PreNarrowingType; @@ -5998,7 +6080,8 @@ void Sema::AddOverloadCandidate( FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions, - ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions) { + ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions, + OverloadCandidateParamOrder PO) { const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>()); assert(Proto && "Functions without a prototype cannot be overloaded"); @@ -6017,25 +6100,14 @@ void Sema::AddOverloadCandidate( AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(), Expr::Classification::makeSimpleLValue(), Args, CandidateSet, SuppressUserConversions, - PartialOverloading, EarlyConversions); + PartialOverloading, EarlyConversions, PO); return; } // We treat a constructor like a non-member function, since its object // argument doesn't participate in overload resolution. } - if (!CandidateSet.isNewCandidate(Function)) - return; - - // C++ [over.match.oper]p3: - // if no operand has a class type, only those non-member functions in the - // lookup set that have a first parameter of type T1 or "reference to - // (possibly cv-qualified) T1", when T1 is an enumeration type, or (if there - // is a right operand) a second parameter of type T2 or "reference to - // (possibly cv-qualified) T2", when T2 is an enumeration type, are - // candidate functions. - if (CandidateSet.getKind() == OverloadCandidateSet::CSK_Operator && - !IsAcceptableNonMemberOperatorCandidate(Context, Function, Args)) + if (!CandidateSet.isNewCandidate(Function, PO)) return; // C++11 [class.copy]p11: [DR1402] @@ -6050,12 +6122,25 @@ void Sema::AddOverloadCandidate( EnterExpressionEvaluationContext Unevaluated( *this, Sema::ExpressionEvaluationContext::Unevaluated); + // C++ [over.match.oper]p3: + // if no operand has a class type, only those non-member functions in the + // lookup set that have a first parameter of type T1 or "reference to + // (possibly cv-qualified) T1", when T1 is an enumeration type, or (if there + // is a right operand) a second parameter of type T2 or "reference to + // (possibly cv-qualified) T2", when T2 is an enumeration type, are + // candidate functions. + if (CandidateSet.getKind() == OverloadCandidateSet::CSK_Operator && + !IsAcceptableNonMemberOperatorCandidate(Context, Function, Args)) + return; + // Add this candidate OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size(), EarlyConversions); Candidate.FoundDecl = FoundDecl; Candidate.Function = Function; Candidate.Viable = true; + Candidate.RewriteKind = + CandidateSet.getRewriteInfo().getRewriteKind(Function, PO); Candidate.IsSurrogate = false; Candidate.IsADLCandidate = IsADLCandidate; Candidate.IgnoreObjectArgument = false; @@ -6155,7 +6240,9 @@ void Sema::AddOverloadCandidate( // Determine the implicit conversion sequences for each of the // arguments. for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) { - if (Candidate.Conversions[ArgIdx].isInitialized()) { + unsigned ConvIdx = + PO == OverloadCandidateParamOrder::Reversed ? 1 - ArgIdx : ArgIdx; + if (Candidate.Conversions[ConvIdx].isInitialized()) { // We already formed a conversion sequence for this parameter during // template argument deduction. } else if (ArgIdx < NumParams) { @@ -6164,12 +6251,12 @@ void Sema::AddOverloadCandidate( // (13.3.3.1) that converts that argument to the corresponding // parameter of F. QualType ParamType = Proto->getParamType(ArgIdx); - Candidate.Conversions[ArgIdx] = TryCopyInitialization( + Candidate.Conversions[ConvIdx] = TryCopyInitialization( *this, Args[ArgIdx], ParamType, SuppressUserConversions, /*InOverloadResolution=*/true, /*AllowObjCWritebackConversion=*/ getLangOpts().ObjCAutoRefCount, AllowExplicitConversions); - if (Candidate.Conversions[ArgIdx].isBad()) { + if (Candidate.Conversions[ConvIdx].isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; return; @@ -6178,7 +6265,7 @@ void Sema::AddOverloadCandidate( // (C++ 13.3.2p2): For the purposes of overload resolution, any // argument for which there is no corresponding parameter is // considered to ""match the ellipsis" (C+ 13.3.3.1.3). - Candidate.Conversions[ArgIdx].setEllipsis(); + Candidate.Conversions[ConvIdx].setEllipsis(); } } @@ -6525,9 +6612,10 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, FunctionArgs = Args.slice(1); } if (FunTmpl) { - AddTemplateOverloadCandidate( - FunTmpl, F.getPair(), ExplicitTemplateArgs, FunctionArgs, - CandidateSet, SuppressUserConversions, PartialOverloading); + AddTemplateOverloadCandidate(FunTmpl, F.getPair(), + ExplicitTemplateArgs, FunctionArgs, + CandidateSet, SuppressUserConversions, + PartialOverloading); } else { AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet, SuppressUserConversions, PartialOverloading); @@ -6538,12 +6626,12 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, /// AddMethodCandidate - Adds a named decl (which is some kind of /// method) as a method candidate to the given overload set. -void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, - QualType ObjectType, +void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef<Expr *> Args, - OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions) { + OverloadCandidateSet &CandidateSet, + bool SuppressUserConversions, + OverloadCandidateParamOrder PO) { NamedDecl *Decl = FoundDecl.getDecl(); CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(Decl->getDeclContext()); @@ -6556,11 +6644,11 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, AddMethodTemplateCandidate(TD, FoundDecl, ActingContext, /*ExplicitArgs*/ nullptr, ObjectType, ObjectClassification, Args, CandidateSet, - SuppressUserConversions); + SuppressUserConversions, false, PO); } else { AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext, ObjectType, ObjectClassification, Args, CandidateSet, - SuppressUserConversions); + SuppressUserConversions, false, None, PO); } } @@ -6579,14 +6667,15 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, bool PartialOverloading, - ConversionSequenceList EarlyConversions) { + ConversionSequenceList EarlyConversions, + OverloadCandidateParamOrder PO) { const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>()); assert(Proto && "Methods without a prototype cannot be overloaded"); assert(!isa<CXXConstructorDecl>(Method) && "Use AddOverloadCandidate for constructors"); - if (!CandidateSet.isNewCandidate(Method)) + if (!CandidateSet.isNewCandidate(Method, PO)) return; // C++11 [class.copy]p23: [DR1402] @@ -6605,6 +6694,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CandidateSet.addCandidate(Args.size() + 1, EarlyConversions); Candidate.FoundDecl = FoundDecl; Candidate.Function = Method; + Candidate.RewriteKind = + CandidateSet.getRewriteInfo().getRewriteKind(Method, PO); Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.ExplicitCallArguments = Args.size(); @@ -6640,12 +6731,13 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, // The implicit object argument is ignored. Candidate.IgnoreObjectArgument = true; else { + unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0; // Determine the implicit conversion sequence for the object // parameter. - Candidate.Conversions[0] = TryObjectArgumentInitialization( + Candidate.Conversions[ConvIdx] = TryObjectArgumentInitialization( *this, CandidateSet.getLocation(), ObjectType, ObjectClassification, Method, ActingContext); - if (Candidate.Conversions[0].isBad()) { + if (Candidate.Conversions[ConvIdx].isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; return; @@ -6664,7 +6756,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, // Determine the implicit conversion sequences for each of the // arguments. for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) { - if (Candidate.Conversions[ArgIdx + 1].isInitialized()) { + unsigned ConvIdx = + PO == OverloadCandidateParamOrder::Reversed ? 0 : (ArgIdx + 1); + if (Candidate.Conversions[ConvIdx].isInitialized()) { // We already formed a conversion sequence for this parameter during // template argument deduction. } else if (ArgIdx < NumParams) { @@ -6673,13 +6767,13 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, // (13.3.3.1) that converts that argument to the corresponding // parameter of F. QualType ParamType = Proto->getParamType(ArgIdx); - Candidate.Conversions[ArgIdx + 1] + Candidate.Conversions[ConvIdx] = TryCopyInitialization(*this, Args[ArgIdx], ParamType, SuppressUserConversions, /*InOverloadResolution=*/true, /*AllowObjCWritebackConversion=*/ getLangOpts().ObjCAutoRefCount); - if (Candidate.Conversions[ArgIdx + 1].isBad()) { + if (Candidate.Conversions[ConvIdx].isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; return; @@ -6688,7 +6782,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, // (C++ 13.3.2p2): For the purposes of overload resolution, any // argument for which there is no corresponding parameter is // considered to "match the ellipsis" (C+ 13.3.3.1.3). - Candidate.Conversions[ArgIdx + 1].setEllipsis(); + Candidate.Conversions[ConvIdx].setEllipsis(); } } @@ -6709,18 +6803,14 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, /// Add a C++ member function template as a candidate to the candidate /// set, using template argument deduction to produce an appropriate member /// function template specialization. -void -Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, - DeclAccessPair FoundDecl, - CXXRecordDecl *ActingContext, - TemplateArgumentListInfo *ExplicitTemplateArgs, - QualType ObjectType, - Expr::Classification ObjectClassification, - ArrayRef<Expr *> Args, - OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions, - bool PartialOverloading) { - if (!CandidateSet.isNewCandidate(MethodTmpl)) +void Sema::AddMethodTemplateCandidate( + FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, + TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, + Expr::Classification ObjectClassification, ArrayRef<Expr *> Args, + OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, + bool PartialOverloading, OverloadCandidateParamOrder PO) { + if (!CandidateSet.isNewCandidate(MethodTmpl, PO)) return; // C++ [over.match.funcs]p7: @@ -6741,13 +6831,15 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, return CheckNonDependentConversions( MethodTmpl, ParamTypes, Args, CandidateSet, Conversions, SuppressUserConversions, ActingContext, ObjectType, - ObjectClassification); + ObjectClassification, PO); })) { OverloadCandidate &Candidate = CandidateSet.addCandidate(Conversions.size(), Conversions); Candidate.FoundDecl = FoundDecl; Candidate.Function = MethodTmpl->getTemplatedDecl(); Candidate.Viable = false; + Candidate.RewriteKind = + CandidateSet.getRewriteInfo().getRewriteKind(Candidate.Function, PO); Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = cast<CXXMethodDecl>(Candidate.Function)->isStatic() || @@ -6771,7 +6863,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl, ActingContext, ObjectType, ObjectClassification, Args, CandidateSet, SuppressUserConversions, PartialOverloading, - Conversions); + Conversions, PO); } /// Add a C++ function template specialization as a candidate @@ -6781,8 +6873,9 @@ void Sema::AddTemplateOverloadCandidate( FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, - bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate) { - if (!CandidateSet.isNewCandidate(FunctionTemplate)) + bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate, + OverloadCandidateParamOrder PO) { + if (!CandidateSet.isNewCandidate(FunctionTemplate, PO)) return; // C++ [over.match.funcs]p7: @@ -6800,15 +6893,17 @@ void Sema::AddTemplateOverloadCandidate( if (TemplateDeductionResult Result = DeduceTemplateArguments( FunctionTemplate, ExplicitTemplateArgs, Args, Specialization, Info, PartialOverloading, [&](ArrayRef<QualType> ParamTypes) { - return CheckNonDependentConversions(FunctionTemplate, ParamTypes, - Args, CandidateSet, Conversions, - SuppressUserConversions); + return CheckNonDependentConversions( + FunctionTemplate, ParamTypes, Args, CandidateSet, Conversions, + SuppressUserConversions, nullptr, QualType(), {}, PO); })) { OverloadCandidate &Candidate = CandidateSet.addCandidate(Conversions.size(), Conversions); Candidate.FoundDecl = FoundDecl; Candidate.Function = FunctionTemplate->getTemplatedDecl(); Candidate.Viable = false; + Candidate.RewriteKind = + CandidateSet.getRewriteInfo().getRewriteKind(Candidate.Function, PO); Candidate.IsSurrogate = false; Candidate.IsADLCandidate = IsADLCandidate; // Ignore the object argument if there is one, since we don't have an object @@ -6833,7 +6928,7 @@ void Sema::AddTemplateOverloadCandidate( AddOverloadCandidate( Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions, PartialOverloading, AllowExplicit, - /*AllowExplicitConversions*/ false, IsADLCandidate, Conversions); + /*AllowExplicitConversions*/ false, IsADLCandidate, Conversions, PO); } /// Check that implicit conversion sequences can be formed for each argument @@ -6844,7 +6939,7 @@ bool Sema::CheckNonDependentConversions( ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet, ConversionSequenceList &Conversions, bool SuppressUserConversions, CXXRecordDecl *ActingContext, QualType ObjectType, - Expr::Classification ObjectClassification) { + Expr::Classification ObjectClassification, OverloadCandidateParamOrder PO) { // FIXME: The cases in which we allow explicit conversions for constructor // arguments never consider calling a constructor template. It's not clear // that is correct. @@ -6867,10 +6962,11 @@ bool Sema::CheckNonDependentConversions( // overload resolution is permitted to sidestep instantiations. if (HasThisConversion && !cast<CXXMethodDecl>(FD)->isStatic() && !ObjectType.isNull()) { - Conversions[0] = TryObjectArgumentInitialization( + unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0; + Conversions[ConvIdx] = TryObjectArgumentInitialization( *this, CandidateSet.getLocation(), ObjectType, ObjectClassification, Method, ActingContext); - if (Conversions[0].isBad()) + if (Conversions[ConvIdx].isBad()) return true; } @@ -6878,14 +6974,17 @@ bool Sema::CheckNonDependentConversions( ++I) { QualType ParamType = ParamTypes[I]; if (!ParamType->isDependentType()) { - Conversions[ThisConversions + I] + unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed + ? 0 + : (ThisConversions + I); + Conversions[ConvIdx] = TryCopyInitialization(*this, Args[I], ParamType, SuppressUserConversions, /*InOverloadResolution=*/true, /*AllowObjCWritebackConversion=*/ getLangOpts().ObjCAutoRefCount, AllowExplicit); - if (Conversions[ThisConversions + I].isBad()) + if (Conversions[ConvIdx].isBad()) return true; } } @@ -6998,7 +7097,7 @@ void Sema::AddConversionCandidate( if (const PointerType *FromPtrType = ImplicitParamType->getAs<PointerType>()) ImplicitParamType = FromPtrType->getPointeeType(); CXXRecordDecl *ConversionContext - = cast<CXXRecordDecl>(ImplicitParamType->getAs<RecordType>()->getDecl()); + = cast<CXXRecordDecl>(ImplicitParamType->castAs<RecordType>()->getDecl()); Candidate.Conversions[0] = TryObjectArgumentInitialization( *this, CandidateSet.getLocation(), From->getType(), @@ -7052,10 +7151,9 @@ void Sema::AddConversionCandidate( // allocator). QualType CallResultType = ConversionType.getNonLValueExprType(Context); - llvm::AlignedCharArray<alignof(CallExpr), sizeof(CallExpr) + sizeof(Stmt *)> - Buffer; + alignas(CallExpr) char Buffer[sizeof(CallExpr) + sizeof(Stmt *)]; CallExpr *TheTemporaryCall = CallExpr::CreateTemporary( - Buffer.buffer, &ConversionFn, CallResultType, VK, From->getBeginLoc()); + Buffer, &ConversionFn, CallResultType, VK, From->getBeginLoc()); ImplicitConversionSequence ICS = TryCopyInitialization(*this, TheTemporaryCall, ToType, @@ -7274,6 +7372,48 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, } } +/// Add all of the non-member operator function declarations in the given +/// function set to the overload candidate set. +void Sema::AddNonMemberOperatorCandidates( + const UnresolvedSetImpl &Fns, ArrayRef<Expr *> Args, + OverloadCandidateSet &CandidateSet, + TemplateArgumentListInfo *ExplicitTemplateArgs) { + for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) { + NamedDecl *D = F.getDecl()->getUnderlyingDecl(); + ArrayRef<Expr *> FunctionArgs = Args; + + FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D); + FunctionDecl *FD = + FunTmpl ? FunTmpl->getTemplatedDecl() : cast<FunctionDecl>(D); + + // Don't consider rewritten functions if we're not rewriting. + if (!CandidateSet.getRewriteInfo().isAcceptableCandidate(FD)) + continue; + + assert(!isa<CXXMethodDecl>(FD) && + "unqualified operator lookup found a member function"); + + if (FunTmpl) { + AddTemplateOverloadCandidate(FunTmpl, F.getPair(), ExplicitTemplateArgs, + FunctionArgs, CandidateSet); + if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD)) + AddTemplateOverloadCandidate( + FunTmpl, F.getPair(), ExplicitTemplateArgs, + {FunctionArgs[1], FunctionArgs[0]}, CandidateSet, false, false, + true, ADLCallKind::NotADL, OverloadCandidateParamOrder::Reversed); + } else { + if (ExplicitTemplateArgs) + continue; + AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet); + if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD)) + AddOverloadCandidate(FD, F.getPair(), + {FunctionArgs[1], FunctionArgs[0]}, CandidateSet, + false, false, true, false, ADLCallKind::NotADL, + None, OverloadCandidateParamOrder::Reversed); + } + } +} + /// Add overload candidates for overloaded operators that are /// member functions. /// @@ -7285,8 +7425,8 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, ArrayRef<Expr *> Args, - OverloadCandidateSet& CandidateSet, - SourceRange OpRange) { + OverloadCandidateSet &CandidateSet, + OverloadCandidateParamOrder PO) { DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); // C++ [over.match.oper]p3: @@ -7321,7 +7461,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, ++Oper) AddMethodCandidate(Oper.getPair(), Args[0]->getType(), Args[0]->Classify(Context), Args.slice(1), - CandidateSet, /*SuppressUserConversion=*/false); + CandidateSet, /*SuppressUserConversion=*/false, PO); } } @@ -7776,7 +7916,7 @@ class BuiltinOperatorOverloadBuilder { static constexpr int ArithmeticTypesCap = 24; SmallVector<CanQualType, ArithmeticTypesCap> ArithmeticTypes; - // Define some indices used to iterate over the arithemetic types in + // Define some indices used to iterate over the arithmetic types in // ArithmeticTypes. The "promoted arithmetic types" are the arithmetic // types are that preserved by promotion (C++ [over.built]p2). unsigned FirstIntegralType, @@ -8126,10 +8266,16 @@ public: if (C->Function->isFunctionTemplateSpecialization()) continue; - QualType FirstParamType = - C->Function->getParamDecl(0)->getType().getUnqualifiedType(); - QualType SecondParamType = - C->Function->getParamDecl(1)->getType().getUnqualifiedType(); + // We interpret "same parameter-type-list" as applying to the + // "synthesized candidate, with the order of the two parameters + // reversed", not to the original function. + bool Reversed = C->RewriteKind & CRK_Reversed; + QualType FirstParamType = C->Function->getParamDecl(Reversed ? 1 : 0) + ->getType() + .getUnqualifiedType(); + QualType SecondParamType = C->Function->getParamDecl(Reversed ? 0 : 1) + ->getType() + .getUnqualifiedType(); // Skip if either parameter isn't of enumeral type. if (!FirstParamType->isEnumeralType() || @@ -8759,7 +8905,7 @@ public: Enum = CandidateTypes[ArgIdx].enumeration_begin(), EnumEnd = CandidateTypes[ArgIdx].enumeration_end(); Enum != EnumEnd; ++Enum) { - if (!(*Enum)->getAs<EnumType>()->getDecl()->isScoped()) + if (!(*Enum)->castAs<EnumType>()->getDecl()->isScoped()) continue; if (!AddedTypes.insert(S.Context.getCanonicalType(*Enum)).second) @@ -9183,6 +9329,7 @@ bool clang::isBetterOverloadCandidate( // A viable function F1 is defined to be a better function than another // viable function F2 if for all arguments i, ICSi(F1) is not a worse // conversion sequence than ICSi(F2), and then... + bool HasWorseConversion = false; for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) { switch (CompareImplicitConversionSequences(S, Loc, Cand1.Conversions[ArgIdx], @@ -9193,6 +9340,24 @@ bool clang::isBetterOverloadCandidate( break; case ImplicitConversionSequence::Worse: + if (Cand1.Function && Cand1.Function == Cand2.Function && + (Cand2.RewriteKind & CRK_Reversed) != 0) { + // Work around large-scale breakage caused by considering reversed + // forms of operator== in C++20: + // + // When comparing a function against its reversed form, if we have a + // better conversion for one argument and a worse conversion for the + // other, we prefer the non-reversed form. + // + // This prevents a conversion function from being considered ambiguous + // with its own reversed form in various where it's only incidentally + // heterogeneous. + // + // We diagnose this as an extension from CreateOverloadedBinOp. + HasWorseConversion = true; + break; + } + // Cand1 can't be better than Cand2. return false; @@ -9206,6 +9371,8 @@ bool clang::isBetterOverloadCandidate( // ICSj(F2), or, if not that, if (HasBetterConversion) return true; + if (HasWorseConversion) + return false; // -- the context is an initialization by user-defined conversion // (see 8.5, 13.3.1.5) and the standard conversion sequence @@ -9273,8 +9440,10 @@ bool clang::isBetterOverloadCandidate( return BetterTemplate == Cand1.Function->getPrimaryTemplate(); } - // FIXME: Work around a defect in the C++17 inheriting constructor wording. - // A derived-class constructor beats an (inherited) base class constructor. + // -- 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. + // FIXME: Implement the "all parameters have the same type" check. bool Cand1IsInherited = dyn_cast_or_null<ConstructorUsingShadowDecl>(Cand1.FoundDecl.getDecl()); bool Cand2IsInherited = @@ -9292,6 +9461,16 @@ bool clang::isBetterOverloadCandidate( // Inherited from sibling base classes: still ambiguous. } + // -- F2 is a rewritten candidate (12.4.1.2) and F1 is not + // -- F1 and F2 are rewritten candidates, and F2 is a synthesized candidate + // with reversed order of parameters and F1 is not + // + // We rank reversed + different operator as worse than just reversed, but + // that comparison can never happen, because we only consider reversing for + // the maximally-rewritten operator (== or <=>). + if (Cand1.RewriteKind != Cand2.RewriteKind) + return Cand1.RewriteKind < Cand2.RewriteKind; + // Check C++17 tie-breakers for deduction guides. { auto *Guide1 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand1.Function); @@ -9425,13 +9604,15 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, const FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext); bool ContainsSameSideCandidate = llvm::any_of(Candidates, [&](OverloadCandidate *Cand) { - return Cand->Function && + // Check viable function only. + return Cand->Viable && Cand->Function && S.IdentifyCUDAPreference(Caller, Cand->Function) == Sema::CFP_SameSide; }); if (ContainsSameSideCandidate) { auto IsWrongSideCandidate = [&](OverloadCandidate *Cand) { - return Cand->Function && + // Check viable function only to avoid unnecessary data copying/moving. + return Cand->Viable && Cand->Function && S.IdentifyCUDAPreference(Caller, Cand->Function) == Sema::CFP_WrongSide; }; @@ -9485,6 +9666,7 @@ namespace { enum OverloadCandidateKind { oc_function, oc_method, + oc_reversed_binary_operator, oc_constructor, oc_implicit_default_constructor, oc_implicit_copy_constructor, @@ -9502,6 +9684,7 @@ enum OverloadCandidateSelect { static std::pair<OverloadCandidateKind, OverloadCandidateSelect> ClassifyOverloadCandidate(Sema &S, NamedDecl *Found, FunctionDecl *Fn, + OverloadCandidateRewriteKind CRK, std::string &Description) { bool isTemplate = Fn->isTemplateDecl() || Found->isTemplateDecl(); @@ -9518,6 +9701,9 @@ ClassifyOverloadCandidate(Sema &S, NamedDecl *Found, FunctionDecl *Fn, }(); OverloadCandidateKind Kind = [&]() { + if (CRK & CRK_Reversed) + return oc_reversed_binary_operator; + if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn)) { if (!Ctor->isImplicit()) { if (isa<ConstructorUsingShadowDecl>(Found)) @@ -9642,6 +9828,7 @@ bool Sema::checkAddressOfFunctionIsAvailable(const FunctionDecl *Function, // Notes the location of an overload candidate. void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn, + OverloadCandidateRewriteKind RewriteKind, QualType DestType, bool TakingAddress) { if (TakingAddress && !checkAddressOfCandidateIsAvailable(*this, Fn)) return; @@ -9651,7 +9838,7 @@ void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn, std::string FnDesc; std::pair<OverloadCandidateKind, OverloadCandidateSelect> KSPair = - ClassifyOverloadCandidate(*this, Found, Fn, FnDesc); + ClassifyOverloadCandidate(*this, Found, Fn, RewriteKind, FnDesc); PartialDiagnostic PD = PDiag(diag::note_ovl_candidate) << (unsigned)KSPair.first << (unsigned)KSPair.second << Fn << FnDesc; @@ -9675,11 +9862,11 @@ void Sema::NoteAllOverloadCandidates(Expr *OverloadedExpr, QualType DestType, I != IEnd; ++I) { if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl()) ) { - NoteOverloadCandidate(*I, FunTmpl->getTemplatedDecl(), DestType, + NoteOverloadCandidate(*I, FunTmpl->getTemplatedDecl(), CRK_None, DestType, TakingAddress); } else if (FunctionDecl *Fun = dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()) ) { - NoteOverloadCandidate(*I, Fun, DestType, TakingAddress); + NoteOverloadCandidate(*I, Fun, CRK_None, DestType, TakingAddress); } } } @@ -9729,7 +9916,8 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, std::string FnDesc; std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair = - ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, FnDesc); + ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Cand->RewriteKind, + FnDesc); Expr *FromExpr = Conv.Bad.FromExpr; QualType FromTy = Conv.Bad.getFromType(); @@ -10001,7 +10189,7 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D, std::string Description; std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair = - ClassifyOverloadCandidate(S, Found, Fn, Description); + ClassifyOverloadCandidate(S, Found, Fn, CRK_None, Description); if (modeCount == 1 && Fn->getParamDecl(0)->getDeclName()) S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity_one) @@ -10298,7 +10486,8 @@ static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) { std::string FnDesc; std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair = - ClassifyOverloadCandidate(S, Cand->FoundDecl, Callee, FnDesc); + ClassifyOverloadCandidate(S, Cand->FoundDecl, Callee, Cand->RewriteKind, + FnDesc); S.Diag(Callee->getLocation(), diag::note_ovl_candidate_bad_target) << (unsigned)FnKindPair.first << (unsigned)ocs_non_template @@ -10416,7 +10605,8 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, if (Fn->isDeleted()) { std::string FnDesc; std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair = - ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, FnDesc); + ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Cand->RewriteKind, + FnDesc); S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted) << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc @@ -10426,7 +10616,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); + S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind); return; } @@ -10459,7 +10649,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); + return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind); case ovl_fail_bad_conversion: { unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0); @@ -10470,7 +10660,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); + return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind); } case ovl_fail_bad_target: @@ -10550,12 +10740,12 @@ static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc, TypeStr += Cand->BuiltinParamTypes[0].getAsString(); if (Cand->Conversions.size() == 1) { TypeStr += ")"; - S.Diag(OpLoc, diag::note_ovl_builtin_unary_candidate) << TypeStr; + S.Diag(OpLoc, diag::note_ovl_builtin_candidate) << TypeStr; } else { TypeStr += ", "; TypeStr += Cand->BuiltinParamTypes[1].getAsString(); TypeStr += ")"; - S.Diag(OpLoc, diag::note_ovl_builtin_binary_candidate) << TypeStr; + S.Diag(OpLoc, diag::note_ovl_builtin_candidate) << TypeStr; } } @@ -10746,8 +10936,10 @@ struct CompareOverloadCandidatesForDisplay { /// CompleteNonViableCandidate - Normally, overload resolution only /// computes up to the first bad conversion. Produces the FixIt set if /// possible. -static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, - ArrayRef<Expr *> Args) { +static void +CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, + ArrayRef<Expr *> Args, + OverloadCandidateSet::CandidateSetKind CSK) { assert(!Cand->Viable); // Don't do anything on failures other than bad conversion. @@ -10775,6 +10967,7 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, bool SuppressUserConversions = false; unsigned ConvIdx = 0; + unsigned ArgIdx = 0; ArrayRef<QualType> ParamTypes; if (Cand->IsSurrogate) { @@ -10782,16 +10975,19 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, = Cand->Surrogate->getConversionType().getNonReferenceType(); if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) ConvType = ConvPtrType->getPointeeType(); - ParamTypes = ConvType->getAs<FunctionProtoType>()->getParamTypes(); - // Conversion 0 is 'this', which doesn't have a corresponding argument. + ParamTypes = ConvType->castAs<FunctionProtoType>()->getParamTypes(); + // Conversion 0 is 'this', which doesn't have a corresponding parameter. ConvIdx = 1; } else if (Cand->Function) { ParamTypes = - Cand->Function->getType()->getAs<FunctionProtoType>()->getParamTypes(); + Cand->Function->getType()->castAs<FunctionProtoType>()->getParamTypes(); if (isa<CXXMethodDecl>(Cand->Function) && !isa<CXXConstructorDecl>(Cand->Function)) { - // Conversion 0 is 'this', which doesn't have a corresponding argument. + // Conversion 0 is 'this', which doesn't have a corresponding parameter. ConvIdx = 1; + if (CSK == OverloadCandidateSet::CSK_Operator) + // Argument 0 is 'this', which doesn't have a corresponding parameter. + ArgIdx = 1; } } else { // Builtin operator. @@ -10800,16 +10996,19 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, } // Fill in the rest of the conversions. - for (unsigned ArgIdx = 0; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) { + bool Reversed = Cand->RewriteKind & CRK_Reversed; + for (unsigned ParamIdx = Reversed ? ParamTypes.size() - 1 : 0; + ConvIdx != ConvCount; + ++ConvIdx, ++ArgIdx, ParamIdx += (Reversed ? -1 : 1)) { if (Cand->Conversions[ConvIdx].isInitialized()) { // We've already checked this conversion. } else if (ArgIdx < ParamTypes.size()) { - if (ParamTypes[ArgIdx]->isDependentType()) + if (ParamTypes[ParamIdx]->isDependentType()) Cand->Conversions[ConvIdx].setAsIdentityConversion( Args[ArgIdx]->getType()); else { Cand->Conversions[ConvIdx] = - TryCopyInitialization(S, Args[ArgIdx], ParamTypes[ArgIdx], + TryCopyInitialization(S, Args[ArgIdx], ParamTypes[ParamIdx], SuppressUserConversions, /*InOverloadResolution=*/true, /*AllowObjCWritebackConversion=*/ @@ -10837,7 +11036,7 @@ SmallVector<OverloadCandidate *, 32> OverloadCandidateSet::CompleteCandidates( if (Cand->Viable) Cands.push_back(Cand); else if (OCD == OCD_AllCandidates) { - CompleteNonViableCandidate(S, Cand, Args); + 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, @@ -11394,7 +11593,7 @@ public: if (FunctionDecl *Fun = dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl())) if (!functionHasPassObjectSizeParams(Fun)) - S.NoteOverloadCandidate(*I, Fun, TargetFunctionType, + S.NoteOverloadCandidate(*I, Fun, CRK_None, TargetFunctionType, /*TakingAddress=*/true); FailedCandidates.NoteCandidates(S, OvlExpr->getBeginLoc()); } @@ -12344,7 +12543,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator); // Add the candidates from the given function set. - AddFunctionCandidates(Fns, ArgsArray, CandidateSet); + AddNonMemberOperatorCandidates(Fns, ArgsArray, CandidateSet); // Add operator candidates that are member functions. AddMemberOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet); @@ -12489,14 +12688,17 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, /// /// \param LHS Left-hand argument. /// \param RHS Right-hand argument. -ExprResult -Sema::CreateOverloadedBinOp(SourceLocation OpLoc, - BinaryOperatorKind Opc, - const UnresolvedSetImpl &Fns, - Expr *LHS, Expr *RHS, bool PerformADL) { +ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, + BinaryOperatorKind Opc, + const UnresolvedSetImpl &Fns, Expr *LHS, + Expr *RHS, bool PerformADL, + bool AllowRewrittenCandidates) { Expr *Args[2] = { LHS, RHS }; LHS=RHS=nullptr; // Please use only Args instead of LHS/RHS couple + if (!getLangOpts().CPlusPlus2a) + AllowRewrittenCandidates = false; + OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc); DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); @@ -12554,23 +12756,61 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); // Build an empty overload set. - OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator); + OverloadCandidateSet CandidateSet( + OpLoc, OverloadCandidateSet::CSK_Operator, + OverloadCandidateSet::OperatorRewriteInfo(Op, AllowRewrittenCandidates)); - // Add the candidates from the given function set. - AddFunctionCandidates(Fns, Args, CandidateSet); + 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) + 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); bool HadMultipleCandidates = (CandidateSet.size() > 1); @@ -12582,11 +12822,57 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // We found a built-in operator or an overloaded operator. FunctionDecl *FnDecl = Best->Function; + bool IsReversed = (Best->RewriteKind & CRK_Reversed); + if (IsReversed) + std::swap(Args[0], Args[1]); + if (FnDecl) { Expr *Base = nullptr; // We matched an overloaded operator. Build a call to that // operator. + OverloadedOperatorKind ChosenOp = + FnDecl->getDeclName().getCXXOverloadedOperator(); + + // C++2a [over.match.oper]p9: + // If a rewritten operator== candidate is selected by overload + // resolution for an operator@, its return type shall be cv bool + if (Best->RewriteKind && ChosenOp == OO_EqualEqual && + !FnDecl->getReturnType()->isBooleanType()) { + Diag(OpLoc, diag::err_ovl_rewrite_equalequal_not_bool) + << FnDecl->getReturnType() << BinaryOperator::getOpcodeStr(Opc) + << Args[0]->getSourceRange() << Args[1]->getSourceRange(); + Diag(FnDecl->getLocation(), diag::note_declared_at); + return ExprError(); + } + + if (AllowRewrittenCandidates && !IsReversed && + CandidateSet.getRewriteInfo().shouldAddReversed(ChosenOp)) { + // We could have reversed this operator, but didn't. Check if the + // reversed form was a viable candidate, and if so, if it had a + // better conversion for either parameter. If so, this call is + // formally ambiguous, and allowing it is an extension. + for (OverloadCandidate &Cand : CandidateSet) { + if (Cand.Viable && Cand.Function == FnDecl && + Cand.RewriteKind & CRK_Reversed) { + for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) { + if (CompareImplicitConversionSequences( + *this, OpLoc, Cand.Conversions[ArgIdx], + Best->Conversions[ArgIdx]) == + ImplicitConversionSequence::Better) { + Diag(OpLoc, diag::ext_ovl_ambiguous_oper_binary_reversed) + << BinaryOperator::getOpcodeStr(Opc) + << Args[0]->getType() << Args[1]->getType() + << Args[0]->getSourceRange() << Args[1]->getSourceRange(); + Diag(FnDecl->getLocation(), + diag::note_ovl_ambiguous_oper_binary_reversed_candidate); + } + } + break; + } + } + } + // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { // Best->Access is only meaningful for class members. @@ -12640,8 +12926,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, ResultTy = ResultTy.getNonLValueExprType(Context); CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create( - Context, Op, FnExpr.get(), Args, ResultTy, VK, OpLoc, FPFeatures, - Best->IsADLCandidate); + Context, ChosenOp, FnExpr.get(), Args, ResultTy, VK, OpLoc, + FPFeatures, Best->IsADLCandidate); if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl)) @@ -12663,7 +12949,46 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, isa<CXXMethodDecl>(FnDecl), OpLoc, TheCall->getSourceRange(), VariadicDoesNotApply); - return MaybeBindToTemporary(TheCall); + ExprResult R = MaybeBindToTemporary(TheCall); + if (R.isInvalid()) + return ExprError(); + + // For a rewritten candidate, we've already reversed the arguments + // if needed. Perform the rest of the rewrite now. + if ((Best->RewriteKind & CRK_DifferentOperator) || + (Op == OO_Spaceship && IsReversed)) { + if (Op == OO_ExclaimEqual) { + assert(ChosenOp == OO_EqualEqual && "unexpected operator name"); + R = CreateBuiltinUnaryOp(OpLoc, UO_LNot, R.get()); + } else { + assert(ChosenOp == OO_Spaceship && "unexpected operator name"); + llvm::APSInt Zero(Context.getTypeSize(Context.IntTy), false); + Expr *ZeroLiteral = + IntegerLiteral::Create(Context, Zero, Context.IntTy, OpLoc); + + Sema::CodeSynthesisContext Ctx; + Ctx.Kind = Sema::CodeSynthesisContext::RewritingOperatorAsSpaceship; + Ctx.Entity = FnDecl; + pushCodeSynthesisContext(Ctx); + + R = CreateOverloadedBinOp( + OpLoc, Opc, Fns, IsReversed ? ZeroLiteral : R.get(), + IsReversed ? R.get() : ZeroLiteral, PerformADL, + /*AllowRewrittenCandidates=*/false); + + popCodeSynthesisContext(); + } + if (R.isInvalid()) + return ExprError(); + } else { + assert(ChosenOp == Op && "unexpected operator name"); + } + + // Make a note in the AST if we did any rewriting. + if (Best->RewriteKind != CRK_None) + R = new (Context) CXXRewrittenBinaryOperator(R.get(), IsReversed); + + return R; } else { // We matched a built-in operator. Convert the arguments, then // break out so that we will build the appropriate built-in @@ -12753,10 +13078,12 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, return ExprError(); } CandidateSet.NoteCandidates( - PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_deleted_oper) - << BinaryOperator::getOpcodeStr(Opc) - << Args[0]->getSourceRange() - << Args[1]->getSourceRange()), + PartialDiagnosticAt( + OpLoc, PDiag(diag::err_ovl_deleted_oper) + << getOperatorSpelling(Best->Function->getDeclName() + .getCXXOverloadedOperator()) + << Args[0]->getSourceRange() + << Args[1]->getSourceRange()), *this, OCD_AllCandidates, Args, BinaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); @@ -13633,8 +13960,8 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R, OverloadCandidateSet CandidateSet(UDSuffixLoc, OverloadCandidateSet::CSK_Normal); - AddFunctionCandidates(R.asUnresolvedSet(), Args, CandidateSet, TemplateArgs, - /*SuppressUserConversions=*/true); + AddNonMemberOperatorCandidates(R.asUnresolvedSet(), Args, CandidateSet, + TemplateArgs); bool HadMultipleCandidates = (CandidateSet.size() > 1); diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 480155df8990..6c680f29da4f 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -196,6 +196,25 @@ static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) { return true; } +static bool DiagnoseNoDiscard(Sema &S, const WarnUnusedResultAttr *A, + SourceLocation Loc, SourceRange R1, + SourceRange R2, bool IsCtor) { + if (!A) + return false; + StringRef Msg = A->getMessage(); + + if (Msg.empty()) { + if (IsCtor) + return S.Diag(Loc, diag::warn_unused_constructor) << A << R1 << R2; + return S.Diag(Loc, diag::warn_unused_result) << A << R1 << R2; + } + + if (IsCtor) + return S.Diag(Loc, diag::warn_unused_constructor_msg) << A << Msg << R1 + << R2; + return S.Diag(Loc, diag::warn_unused_result_msg) << A << Msg << R1 << R2; +} + void Sema::DiagnoseUnusedExprResult(const Stmt *S) { if (const LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S)) return DiagnoseUnusedExprResult(Label->getSubStmt()); @@ -254,14 +273,19 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { return; E = WarnExpr; + if (const auto *Cast = dyn_cast<CastExpr>(E)) + if (Cast->getCastKind() == CK_NoOp || + Cast->getCastKind() == CK_ConstructorConversion) + E = Cast->getSubExpr()->IgnoreImpCasts(); + if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { if (E->getType()->isVoidType()) return; - if (const Attr *A = CE->getUnusedResultAttr(Context)) { - Diag(Loc, diag::warn_unused_result) << A << R1 << R2; + if (DiagnoseNoDiscard(*this, cast_or_null<WarnUnusedResultAttr>( + CE->getUnusedResultAttr(Context)), + Loc, R1, R2, /*isCtor=*/false)) return; - } // If the callee has attribute pure, const, or warn_unused_result, warn with // a more specific message to make it clear what is happening. If the call @@ -279,9 +303,24 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { return; } } + } else if (const auto *CE = dyn_cast<CXXConstructExpr>(E)) { + if (const CXXConstructorDecl *Ctor = CE->getConstructor()) { + const auto *A = Ctor->getAttr<WarnUnusedResultAttr>(); + A = A ? A : Ctor->getParent()->getAttr<WarnUnusedResultAttr>(); + if (DiagnoseNoDiscard(*this, A, Loc, R1, R2, /*isCtor=*/true)) + return; + } + } else if (const auto *ILE = dyn_cast<InitListExpr>(E)) { + if (const TagDecl *TD = ILE->getType()->getAsTagDecl()) { + + if (DiagnoseNoDiscard(*this, TD->getAttr<WarnUnusedResultAttr>(), Loc, R1, + R2, /*isCtor=*/false)) + return; + } } else if (ShouldSuppress) return; + E = WarnExpr; if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) { if (getLangOpts().ObjCAutoRefCount && ME->isDelegateInitCall()) { Diag(Loc, diag::err_arc_unused_init_message) << R1; @@ -289,10 +328,9 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { } const ObjCMethodDecl *MD = ME->getMethodDecl(); if (MD) { - if (const auto *A = MD->getAttr<WarnUnusedResultAttr>()) { - Diag(Loc, diag::warn_unused_result) << A << R1 << R2; + if (DiagnoseNoDiscard(*this, MD->getAttr<WarnUnusedResultAttr>(), Loc, R1, + R2, /*isCtor=*/false)) return; - } } } else if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) { const Expr *Source = POE->getSyntacticForm(); @@ -392,45 +430,44 @@ Sema::ActOnCaseExpr(SourceLocation CaseLoc, ExprResult Val) { // If we're not inside a switch, let the 'case' statement handling diagnose // this. Just clean up after the expression as best we can. - if (!getCurFunction()->SwitchStack.empty()) { - Expr *CondExpr = - getCurFunction()->SwitchStack.back().getPointer()->getCond(); - if (!CondExpr) - return ExprError(); - QualType CondType = CondExpr->getType(); - - auto CheckAndFinish = [&](Expr *E) { - if (CondType->isDependentType() || E->isTypeDependent()) - return ExprResult(E); - - if (getLangOpts().CPlusPlus11) { - // C++11 [stmt.switch]p2: the constant-expression shall be a converted - // constant expression of the promoted type of the switch condition. - llvm::APSInt TempVal; - return CheckConvertedConstantExpression(E, CondType, TempVal, - CCEK_CaseValue); - } + if (getCurFunction()->SwitchStack.empty()) + return ActOnFinishFullExpr(Val.get(), Val.get()->getExprLoc(), false, + getLangOpts().CPlusPlus11); - ExprResult ER = E; - if (!E->isValueDependent()) - ER = VerifyIntegerConstantExpression(E); - if (!ER.isInvalid()) - ER = DefaultLvalueConversion(ER.get()); - if (!ER.isInvalid()) - ER = ImpCastExprToType(ER.get(), CondType, CK_IntegralCast); - return ER; - }; + Expr *CondExpr = + getCurFunction()->SwitchStack.back().getPointer()->getCond(); + if (!CondExpr) + return ExprError(); + QualType CondType = CondExpr->getType(); - ExprResult Converted = CorrectDelayedTyposInExpr(Val, CheckAndFinish); - if (Converted.get() == Val.get()) - Converted = CheckAndFinish(Val.get()); - if (Converted.isInvalid()) - return ExprError(); - Val = Converted; - } + auto CheckAndFinish = [&](Expr *E) { + if (CondType->isDependentType() || E->isTypeDependent()) + return ExprResult(E); + + if (getLangOpts().CPlusPlus11) { + // C++11 [stmt.switch]p2: the constant-expression shall be a converted + // constant expression of the promoted type of the switch condition. + llvm::APSInt TempVal; + return CheckConvertedConstantExpression(E, CondType, TempVal, + CCEK_CaseValue); + } - return ActOnFinishFullExpr(Val.get(), Val.get()->getExprLoc(), false, - getLangOpts().CPlusPlus11); + ExprResult ER = E; + if (!E->isValueDependent()) + ER = VerifyIntegerConstantExpression(E); + if (!ER.isInvalid()) + ER = DefaultLvalueConversion(ER.get()); + if (!ER.isInvalid()) + ER = ImpCastExprToType(ER.get(), CondType, CK_IntegralCast); + if (!ER.isInvalid()) + ER = ActOnFinishFullExpr(ER.get(), ER.get()->getExprLoc(), false); + return ER; + }; + + ExprResult Converted = CorrectDelayedTyposInExpr(Val, CheckAndFinish); + if (Converted.get() == Val.get()) + Converted = CheckAndFinish(Val.get()); + return Converted; } StmtResult @@ -926,7 +963,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // condition is constant. llvm::APSInt ConstantCondValue; bool HasConstantCond = false; - if (!HasDependentValue && !TheDefaultStmt) { + if (!TheDefaultStmt) { Expr::EvalResult Result; HasConstantCond = CondExpr->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects); @@ -2637,6 +2674,11 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, if (Kind == BFRK_Check) return StmtResult(); + // In OpenMP loop region loop control variable must be private. Perform + // analysis of first part (if any). + if (getLangOpts().OpenMP >= 50 && BeginDeclStmt.isUsable()) + ActOnOpenMPLoopInitialization(ForLoc, BeginDeclStmt.get()); + return new (Context) CXXForRangeStmt( InitStmt, RangeDS, cast_or_null<DeclStmt>(BeginDeclStmt.get()), cast_or_null<DeclStmt>(EndDeclStmt.get()), NotEqExpr.get(), @@ -3268,18 +3310,18 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { } assert(!FnRetType.isNull()); - if (BlockScopeInfo *CurBlock = dyn_cast<BlockScopeInfo>(CurCap)) { - if (CurBlock->FunctionType->getAs<FunctionType>()->getNoReturnAttr()) { + if (auto *CurBlock = dyn_cast<BlockScopeInfo>(CurCap)) { + if (CurBlock->FunctionType->castAs<FunctionType>()->getNoReturnAttr()) { Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr); return StmtError(); } - } else if (CapturedRegionScopeInfo *CurRegion = - dyn_cast<CapturedRegionScopeInfo>(CurCap)) { + } else if (auto *CurRegion = dyn_cast<CapturedRegionScopeInfo>(CurCap)) { Diag(ReturnLoc, diag::err_return_in_captured_stmt) << CurRegion->getRegionName(); return StmtError(); } else { assert(CurLambda && "unknown kind of captured scope"); - if (CurLambda->CallOperator->getType()->getAs<FunctionType>() + if (CurLambda->CallOperator->getType() + ->castAs<FunctionType>() ->getNoReturnAttr()) { Diag(ReturnLoc, diag::err_noreturn_lambda_has_return_expr); return StmtError(); @@ -3463,6 +3505,14 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, return true; } + // CUDA: Kernel function must have 'void' return type. + if (getLangOpts().CUDA) + if (FD->hasAttr<CUDAGlobalAttr>() && !Deduced->isVoidType()) { + Diag(FD->getLocation(), diag::err_kern_type_not_void_return) + << FD->getType() << FD->getSourceRange(); + return true; + } + // If a function with a declared return type that contains a placeholder type // has multiple return statements, the return type is deduced for each return // statement. [...] if the type deduced is not the same in each deduction, @@ -4296,7 +4346,8 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, CapturedRegionKind Kind, - ArrayRef<CapturedParamNameType> Params) { + ArrayRef<CapturedParamNameType> Params, + unsigned OpenMPCaptureLevel) { CapturedDecl *CD = nullptr; RecordDecl *RD = CreateCapturedStmtRecordDecl(CD, Loc, Params.size()); @@ -4341,7 +4392,7 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, CD->setContextParam(ParamNum, Param); } // Enter the capturing scope for this captured region. - PushCapturedRegionScope(CurScope, CD, RD, Kind); + PushCapturedRegionScope(CurScope, CD, RD, Kind, OpenMPCaptureLevel); if (CurScope) PushDeclContext(CurScope, CD); diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp index b123a739a7ab..9b051e02d127 100644 --- a/lib/Sema/SemaStmtAsm.cpp +++ b/lib/Sema/SemaStmtAsm.cpp @@ -383,25 +383,19 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, } else if (Info.requiresImmediateConstant() && !Info.allowsRegister()) { if (!InputExpr->isValueDependent()) { Expr::EvalResult EVResult; - if (!InputExpr->EvaluateAsRValue(EVResult, Context, true)) - return StmtError( - Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected) - << Info.getConstraintStr() << InputExpr->getSourceRange()); - - // For compatibility with GCC, we also allow pointers that would be - // integral constant expressions if they were cast to int. - llvm::APSInt IntResult; - if (!EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(), - Context)) - return StmtError( - Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected) - << Info.getConstraintStr() << InputExpr->getSourceRange()); - - if (!Info.isValidAsmImmediate(IntResult)) - return StmtError(Diag(InputExpr->getBeginLoc(), - diag::err_invalid_asm_value_for_constraint) - << IntResult.toString(10) << Info.getConstraintStr() - << InputExpr->getSourceRange()); + if (InputExpr->EvaluateAsRValue(EVResult, Context, true)) { + // For compatibility with GCC, we also allow pointers that would be + // integral constant expressions if they were cast to int. + llvm::APSInt IntResult; + if (EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(), + Context)) + if (!Info.isValidAsmImmediate(IntResult)) + return StmtError(Diag(InputExpr->getBeginLoc(), + diag::err_invalid_asm_value_for_constraint) + << IntResult.toString(10) + << Info.getConstraintStr() + << InputExpr->getSourceRange()); + } } } else { diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp index 791c52c2d913..3d91893b4065 100644 --- a/lib/Sema/SemaStmtAttr.cpp +++ b/lib/Sema/SemaStmtAttr.cpp @@ -23,8 +23,7 @@ using namespace sema; static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const ParsedAttr &A, SourceRange Range) { - FallThroughAttr Attr(A.getRange(), S.Context, - A.getAttributeSpellingListIndex()); + FallThroughAttr Attr(S.Context, A); if (!isa<NullStmt>(St)) { S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target) << Attr.getSpelling() << St->getBeginLoc(); @@ -45,10 +44,10 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const ParsedAttr &A, // about using it as an extension. if (!S.getLangOpts().CPlusPlus17 && A.isCXX11Attribute() && !A.getScopeName()) - S.Diag(A.getLoc(), diag::ext_cxx17_attr) << A.getName(); + S.Diag(A.getLoc(), diag::ext_cxx17_attr) << A; FnScope->setHasFallthroughStmt(); - return ::new (S.Context) auto(Attr); + return ::new (S.Context) FallThroughAttr(S.Context, A); } static Attr *handleSuppressAttr(Sema &S, Stmt *St, const ParsedAttr &A, @@ -71,8 +70,7 @@ static Attr *handleSuppressAttr(Sema &S, Stmt *St, const ParsedAttr &A, } return ::new (S.Context) SuppressAttr( - A.getRange(), S.Context, DiagnosticIdentifiers.data(), - DiagnosticIdentifiers.size(), A.getAttributeSpellingListIndex()); + S.Context, A, DiagnosticIdentifiers.data(), DiagnosticIdentifiers.size()); } static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A, @@ -97,8 +95,6 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A, return nullptr; } - LoopHintAttr::Spelling Spelling = - LoopHintAttr::Spelling(A.getAttributeSpellingListIndex()); LoopHintAttr::OptionType Option; LoopHintAttr::LoopHintState State; @@ -133,6 +129,7 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A, .Case("vectorize", LoopHintAttr::Vectorize) .Case("vectorize_width", LoopHintAttr::VectorizeWidth) .Case("interleave", LoopHintAttr::Interleave) + .Case("vectorize_predicate", LoopHintAttr::VectorizePredicate) .Case("interleave_count", LoopHintAttr::InterleaveCount) .Case("unroll", LoopHintAttr::Unroll) .Case("unroll_count", LoopHintAttr::UnrollCount) @@ -151,6 +148,7 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A, State = LoopHintAttr::Numeric; } else if (Option == LoopHintAttr::Vectorize || Option == LoopHintAttr::Interleave || + Option == LoopHintAttr::VectorizePredicate || Option == LoopHintAttr::Unroll || Option == LoopHintAttr::Distribute || Option == LoopHintAttr::PipelineDisabled) { @@ -169,8 +167,7 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A, llvm_unreachable("bad loop hint"); } - return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State, - ValueExpr, A.getRange()); + return LoopHintAttr::CreateImplicit(S.Context, Option, State, ValueExpr, A); } static void @@ -189,7 +186,8 @@ CheckForIncompatibleAttributes(Sema &S, const LoopHintAttr *StateAttr; const LoopHintAttr *NumericAttr; } HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, - {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}}; + {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, + {nullptr, nullptr}}; for (const auto *I : Attrs) { const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I); @@ -205,7 +203,8 @@ CheckForIncompatibleAttributes(Sema &S, Unroll, UnrollAndJam, Distribute, - Pipeline + Pipeline, + VectorizePredicate } Category; switch (Option) { case LoopHintAttr::Vectorize: @@ -232,6 +231,9 @@ CheckForIncompatibleAttributes(Sema &S, case LoopHintAttr::PipelineInitiationInterval: Category = Pipeline; break; + case LoopHintAttr::VectorizePredicate: + Category = VectorizePredicate; + break; }; assert(Category < sizeof(HintAttrs) / sizeof(HintAttrs[0])); @@ -240,6 +242,7 @@ CheckForIncompatibleAttributes(Sema &S, if (Option == LoopHintAttr::Vectorize || Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll || Option == LoopHintAttr::UnrollAndJam || + Option == LoopHintAttr::VectorizePredicate || Option == LoopHintAttr::PipelineDisabled || Option == LoopHintAttr::Distribute) { // Enable|Disable|AssumeSafety hint. For example, vectorize(enable). @@ -322,7 +325,7 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A, S.Diag(A.getLoc(), A.isDeclspecAttribute() ? (unsigned)diag::warn_unhandled_ms_attribute_ignored : (unsigned)diag::warn_unknown_attribute_ignored) - << A.getName(); + << A; return nullptr; case ParsedAttr::AT_FallThrough: return handleFallThroughAttr(S, St, A, Range); @@ -336,7 +339,7 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A, // if we're here, then we parsed a known attribute, but didn't recognize // it as a statement attribute => it is declaration attribute S.Diag(A.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt) - << A.getName() << St->getBeginLoc(); + << A << St->getBeginLoc(); return nullptr; } } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 3212281cc34d..3f2d38630c36 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -20,9 +20,11 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/Stack.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/Overload.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaInternal.h" @@ -44,27 +46,7 @@ clang::getTemplateParamsRange(TemplateParameterList const * const *Ps, return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc()); } -namespace clang { -/// [temp.constr.decl]p2: A template's associated constraints are -/// defined as a single constraint-expression derived from the introduced -/// constraint-expressions [ ... ]. -/// -/// \param Params The template parameter list and optional requires-clause. -/// -/// \param FD The underlying templated function declaration for a function -/// template. -static Expr *formAssociatedConstraints(TemplateParameterList *Params, - FunctionDecl *FD); -} - -static Expr *clang::formAssociatedConstraints(TemplateParameterList *Params, - FunctionDecl *FD) { - // FIXME: Concepts: collect additional introduced constraint-expressions - assert(!FD && "Cannot collect constraints from function declaration yet."); - return Params->getRequiresClause(); -} - -/// Determine whether the declaration found is acceptable as the name +/// \brief Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, /// returns null. /// @@ -362,13 +344,27 @@ bool Sema::LookupTemplateName(LookupResult &Found, // x->B::f, and we are looking into the type of the object. assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); LookupCtx = computeDeclContext(ObjectType); - IsDependent = !LookupCtx; + IsDependent = !LookupCtx && ObjectType->isDependentType(); assert((IsDependent || !ObjectType->isIncompleteType() || ObjectType->castAs<TagType>()->isBeingDefined()) && "Caller should have completed object type"); - // Template names cannot appear inside an Objective-C class or object type. - if (ObjectType->isObjCObjectOrInterfaceType()) { + // Template names cannot appear inside an Objective-C class or object type + // or a vector type. + // + // FIXME: This is wrong. For example: + // + // template<typename T> using Vec = T __attribute__((ext_vector_type(4))); + // Vec<int> vi; + // vi.Vec<int>::~Vec<int>(); + // + // ... should be accepted but we will not treat 'Vec' as a template name + // here. The right thing to do would be to check if the name is a valid + // vector component name, and look up a template name if not. And similarly + // for lookups into Objective-C class and object types, where the same + // problem can arise. + if (ObjectType->isObjCObjectOrInterfaceType() || + ObjectType->isVectorType()) { Found.clear(); return false; } @@ -630,7 +626,7 @@ void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName, } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<TemplateCandidateFilter>(*this); + return std::make_unique<TemplateCandidateFilter>(*this); } }; @@ -720,9 +716,13 @@ Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs) { + // DependentScopeDeclRefExpr::Create requires a valid QualifierLoc + NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); + if (!QualifierLoc) + return ExprError(); + return DependentScopeDeclRefExpr::Create( - Context, SS.getWithLocInContext(Context), TemplateKWLoc, NameInfo, - TemplateArgs); + Context, QualifierLoc, TemplateKWLoc, NameInfo, TemplateArgs); } @@ -830,15 +830,14 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation, void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) { assert(PrevDecl->isTemplateParameter() && "Not a template parameter"); - // Microsoft Visual C++ permits template parameters to be shadowed. - if (getLangOpts().MicrosoftExt) - return; - // C++ [temp.local]p4: // A template-parameter shall not be redeclared within its // scope (including nested scopes). - Diag(Loc, diag::err_template_param_shadow) - << cast<NamedDecl>(PrevDecl)->getDeclName(); + // + // Make this a warning when MSVC compatibility is requested. + unsigned DiagId = getLangOpts().MSVCCompat ? diag::ext_template_param_shadow + : diag::err_template_param_shadow; + Diag(Loc, DiagId) << cast<NamedDecl>(PrevDecl)->getDeclName(); Diag(PrevDecl->getLocation(), diag::note_template_param_here); } @@ -987,17 +986,16 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename, assert(S->isTemplateParamScope() && "Template type parameter not in template parameter scope!"); - SourceLocation Loc = ParamNameLoc; - if (!ParamName) - Loc = KeyLoc; - bool IsParameterPack = EllipsisLoc.isValid(); - TemplateTypeParmDecl *Param - = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(), - KeyLoc, Loc, Depth, Position, ParamName, - Typename, IsParameterPack); + TemplateTypeParmDecl *Param = TemplateTypeParmDecl::Create( + Context, Context.getTranslationUnitDecl(), KeyLoc, ParamNameLoc, Depth, + Position, ParamName, Typename, IsParameterPack); Param->setAccess(AS_public); + if (Param->isParameterPack()) + if (auto *LSI = getEnclosingLambda()) + LSI->LocalPacks.push_back(Param); + if (ParamName) { maybeDiagnoseTemplateParameterShadow(*this, S, ParamNameLoc, ParamName); @@ -1022,7 +1020,7 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename, assert(DefaultTInfo && "expected source information for type"); // Check for unexpanded parameter packs. - if (DiagnoseUnexpandedParameterPack(Loc, DefaultTInfo, + if (DiagnoseUnexpandedParameterPack(ParamNameLoc, DefaultTInfo, UPPC_DefaultArgument)) return Param; @@ -1082,9 +1080,6 @@ QualType Sema::CheckNonTypeTemplateParameterType(QualType T, T->isMemberPointerType() || // -- std::nullptr_t. T->isNullPtrType() || - // If T is a dependent type, we can't do the check now, so we - // assume that it is well-formed. - T->isDependentType() || // Allow use of auto in template parameter declarations. T->isUndeducedType()) { // C++ [temp.param]p5: The top-level cv-qualifiers on the template-parameter @@ -1097,9 +1092,18 @@ QualType Sema::CheckNonTypeTemplateParameterType(QualType T, // A non-type template-parameter of type "array of T" or // "function returning T" is adjusted to be of type "pointer to // T" or "pointer to function returning T", respectively. - else if (T->isArrayType() || T->isFunctionType()) + if (T->isArrayType() || T->isFunctionType()) return Context.getDecayedType(T); + // If T is a dependent type, we can't do the check now, so we + // assume that it is well-formed. Note that stripping off the + // qualifiers here is not really correct if T turns out to be + // an array type, but we'll recompute the type everywhere it's + // used during instantiation, so that should be OK. (Using the + // qualified type is equally wrong.) + if (T->isDependentType()) + return T.getUnqualifiedType(); + Diag(Loc, diag::err_template_nontype_parm_bad_type) << T; @@ -1196,6 +1200,10 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, if (Invalid) Param->setInvalidDecl(); + if (Param->isParameterPack()) + if (auto *LSI = getEnclosingLambda()) + LSI->LocalPacks.push_back(Param); + if (ParamName) { maybeDiagnoseTemplateParameterShadow(*this, S, D.getIdentifierLoc(), ParamName); @@ -1259,6 +1267,10 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(Scope* S, Name, Params); Param->setAccess(AS_public); + if (Param->isParameterPack()) + if (auto *LSI = getEnclosingLambda()) + LSI->LocalPacks.push_back(Param); + // If the template template parameter has a name, then link the identifier // into the scope and lookup mechanisms. if (Name) { @@ -1502,9 +1514,6 @@ DeclResult Sema::CheckClassTemplate( } } - // TODO Memory management; associated constraints are not always stored. - Expr *const CurAC = formAssociatedConstraints(TemplateParams, nullptr); - if (PrevClassTemplate) { // Ensure that the template parameter lists are compatible. Skip this check // for a friend in a dependent context: the template parameter list itself @@ -1516,30 +1525,6 @@ DeclResult Sema::CheckClassTemplate( TPL_TemplateMatch)) return true; - // Check for matching associated constraints on redeclarations. - const Expr *const PrevAC = PrevClassTemplate->getAssociatedConstraints(); - const bool RedeclACMismatch = [&] { - if (!(CurAC || PrevAC)) - return false; // Nothing to check; no mismatch. - if (CurAC && PrevAC) { - llvm::FoldingSetNodeID CurACInfo, PrevACInfo; - CurAC->Profile(CurACInfo, Context, /*Canonical=*/true); - PrevAC->Profile(PrevACInfo, Context, /*Canonical=*/true); - if (CurACInfo == PrevACInfo) - return false; // All good; no mismatch. - } - return true; - }(); - - if (RedeclACMismatch) { - Diag(CurAC ? CurAC->getBeginLoc() : NameLoc, - diag::err_template_different_associated_constraints); - Diag(PrevAC ? PrevAC->getBeginLoc() : PrevClassTemplate->getLocation(), - diag::note_template_prev_declaration) - << /*declaration*/ 0; - return true; - } - // C++ [temp.class]p4: // In a redeclaration, partial specialization, explicit // specialization or explicit instantiation of a class template, @@ -1643,15 +1628,10 @@ DeclResult Sema::CheckClassTemplate( AddMsStructLayoutForRecord(NewClass); } - // Attach the associated constraints when the declaration will not be part of - // a decl chain. - Expr *const ACtoAttach = - PrevClassTemplate && ShouldAddRedecl ? nullptr : CurAC; - ClassTemplateDecl *NewTemplate = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, DeclarationName(Name), TemplateParams, - NewClass, ACtoAttach); + NewClass); if (ShouldAddRedecl) NewTemplate->setPreviousDecl(PrevClassTemplate); @@ -1690,6 +1670,7 @@ DeclResult Sema::CheckClassTemplate( mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl()); AddPushedVisibilityAttribute(NewClass); + inferGslOwnerPointerAttribute(NewClass); if (TUK != TUK_Friend) { // Per C++ [basic.scope.temp]p2, skip the template parameter scopes. @@ -3440,7 +3421,7 @@ bool Sema::resolveAssumedTemplateNameAsType(Scope *S, TemplateName &Name, getAsTypeTemplateDecl(TC.getCorrectionDecl()); } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<CandidateCallback>(*this); + return std::make_unique<CandidateCallback>(*this); } } FilterCCC; @@ -4239,14 +4220,47 @@ void Sema::diagnoseMissingTemplateArguments(TemplateName Name, ExprResult Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, - const DeclarationNameInfo &NameInfo, - ConceptDecl *Template, - SourceLocation TemplateLoc, + SourceLocation TemplateKWLoc, + SourceLocation ConceptNameLoc, + NamedDecl *FoundDecl, + ConceptDecl *NamedConcept, const TemplateArgumentListInfo *TemplateArgs) { - // TODO: Do concept specialization here. - Diag(NameInfo.getBeginLoc(), diag::err_concept_not_implemented) << - "concept specialization"; - return ExprError(); + assert(NamedConcept && "A concept template id without a template?"); + + llvm::SmallVector<TemplateArgument, 4> Converted; + if (CheckTemplateArgumentList(NamedConcept, ConceptNameLoc, + const_cast<TemplateArgumentListInfo&>(*TemplateArgs), + /*PartialTemplateArgs=*/false, Converted, + /*UpdateArgsWithConversion=*/false)) + return ExprError(); + + Optional<bool> IsSatisfied; + bool AreArgsDependent = false; + for (TemplateArgument &Arg : Converted) { + if (Arg.isDependent()) { + AreArgsDependent = true; + 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)) + return ExprError(); + IsSatisfied = Satisfied; + } + return ConceptSpecializationExpr::Create(Context, + SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{}, + TemplateKWLoc, ConceptNameLoc, FoundDecl, NamedConcept, + ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), Converted, + IsSatisfied); } ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, @@ -4289,10 +4303,11 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, TemplateKWLoc, TemplateArgs); } - if (R.getAsSingle<ConceptDecl>() && !AnyDependentArguments()) { - return CheckConceptTemplateId(SS, R.getLookupNameInfo(), - R.getAsSingle<ConceptDecl>(), - TemplateKWLoc, TemplateArgs); + if (R.getAsSingle<ConceptDecl>()) { + return CheckConceptTemplateId(SS, TemplateKWLoc, + R.getLookupNameInfo().getBeginLoc(), + R.getFoundDecl(), + R.getAsSingle<ConceptDecl>(), TemplateArgs); } // We don't want lookup warnings at this point. @@ -4678,6 +4693,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, for (unsigned i = 0, e = Param->getDepth(); i != e; ++i) TemplateArgLists.addOuterTemplateArguments(None); + Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); EnterExpressionEvaluationContext ConstantEvaluated( SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); return SemaRef.SubstExpr(Param->getDefaultArgument(), TemplateArgLists); @@ -4895,9 +4911,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, if (NTTP->isParameterPack() && NTTP->isExpandedParameterPack()) NTTPType = NTTP->getExpansionType(ArgumentPackIndex); - // FIXME: Do we need to substitute into parameters here if they're - // instantiation-dependent but not dependent? - if (NTTPType->isDependentType() && + if (NTTPType->isInstantiationDependentType() && !isa<TemplateTemplateParmDecl>(Template) && !Template->getDeclContext()->isDependentContext()) { // Do substitution on the type of the non-type template parameter. @@ -5471,7 +5485,7 @@ namespace { bool Visit##Class##Type(const Class##Type *) { return false; } #define NON_CANONICAL_TYPE(Class, Parent) \ bool Visit##Class##Type(const Class##Type *) { return false; } -#include "clang/AST/TypeNodes.def" +#include "clang/AST/TypeNodes.inc" bool VisitTagDecl(const TagDecl *Tag); bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS); @@ -5847,7 +5861,7 @@ static bool CheckTemplateArgumentIsCompatibleWithParameter( Expr *Arg, QualType ArgType) { bool ObjCLifetimeConversion; if (ParamType->isPointerType() && - !ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType() && + !ParamType->castAs<PointerType>()->getPointeeType()->isFunctionType() && S.IsQualificationConversion(ArgType, ParamType, false, ObjCLifetimeConversion)) { // For pointer-to-object types, qualification conversions are @@ -6399,8 +6413,11 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } // If either the parameter has a dependent type or the argument is - // type-dependent, there's nothing we can check now. - if (ParamType->isDependentType() || Arg->isTypeDependent()) { + // type-dependent, there's nothing we can check now. The argument only + // contains an unexpanded pack during partial ordering, and there's + // nothing more we can check in that case. + if (ParamType->isDependentType() || Arg->isTypeDependent() || + Arg->containsUnexpandedParameterPack()) { // Force the argument to the type of the parameter to maintain invariants. auto *PE = dyn_cast<PackExpansionExpr>(Arg); if (PE) @@ -6720,20 +6737,20 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // overloaded functions (or a pointer to such), the matching // function is selected from the set (13.4). (ParamType->isPointerType() && - ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType()) || + ParamType->castAs<PointerType>()->getPointeeType()->isFunctionType()) || // -- For a non-type template-parameter of type reference to // function, no conversions apply. If the template-argument // represents a set of overloaded functions, the matching // function is selected from the set (13.4). (ParamType->isReferenceType() && - ParamType->getAs<ReferenceType>()->getPointeeType()->isFunctionType()) || + ParamType->castAs<ReferenceType>()->getPointeeType()->isFunctionType()) || // -- For a non-type template-parameter of type pointer to // member function, no conversions apply. If the // template-argument represents a set of overloaded member // functions, the matching member function is selected from // the set (13.4). (ParamType->isMemberPointerType() && - ParamType->getAs<MemberPointerType>()->getPointeeType() + ParamType->castAs<MemberPointerType>()->getPointeeType() ->isFunctionType())) { if (Arg->getType() == Context.OverloadTy) { @@ -7198,6 +7215,9 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, TemplateArgLoc); } + // TODO: Concepts: Match immediately-introduced-constraint for type + // constraints + return true; } @@ -7223,6 +7243,15 @@ 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. /// @@ -7312,6 +7341,27 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, return false; } + if (Kind != TPL_TemplateTemplateArgumentMatch) { + const Expr *NewRC = New->getRequiresClause(); + const Expr *OldRC = Old->getRequiresClause(); + if (!NewRC != !OldRC) { + if (Complain) + DiagnoseTemplateParameterListRequiresClauseMismatch(*this, New, Old); + return false; + } + + if (NewRC) { + llvm::FoldingSetNodeID OldRCID, NewRCID; + OldRC->Profile(OldRCID, Context, /*Canonical=*/true); + NewRC->Profile(NewRCID, Context, /*Canonical=*/true); + if (OldRCID != NewRCID) { + if (Complain) + DiagnoseTemplateParameterListRequiresClauseMismatch(*this, New, Old); + return false; + } + } + } + return true; } @@ -8020,24 +8070,10 @@ Decl *Sema::ActOnConceptDefinition(Scope *S, ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, NameLoc, Name, TemplateParameterLists.front(), ConstraintExpr); - - if (!ConstraintExpr->isTypeDependent() && - ConstraintExpr->getType() != Context.BoolTy) { - // C++2a [temp.constr.atomic]p3: - // E shall be a constant expression of type bool. - // TODO: Do this check for individual atomic constraints - // and not the constraint expression. Probably should do it in - // ParseConstraintExpression. - Diag(ConstraintExpr->getSourceRange().getBegin(), - diag::err_concept_initialized_with_non_bool_type) - << ConstraintExpr->getType(); - NewDecl->setInvalidDecl(); - } - - if (NewDecl->getAssociatedConstraints()) { + + if (NewDecl->hasAssociatedConstraints()) { // C++2a [temp.concept]p4: // A concept shall not have associated constraints. - // TODO: Make a test once we have actual associated constraints. Diag(NameLoc, diag::err_concept_no_associated_constraints); NewDecl->setInvalidDecl(); } @@ -8453,7 +8489,7 @@ bool Sema::CheckFunctionTemplateSpecialization( // candidates at once, to get proper sorting and limiting. for (auto *OldND : Previous) { if (auto *OldFD = dyn_cast<FunctionDecl>(OldND->getUnderlyingDecl())) - NoteOverloadCandidate(OldND, OldFD, FD->getType(), false); + NoteOverloadCandidate(OldND, OldFD, CRK_None, FD->getType(), false); } FailedCandidates.NoteCandidates(*this, FD->getLocation()); return true; @@ -10282,7 +10318,7 @@ void Sema::MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD, if (!FD) return; - auto LPT = llvm::make_unique<LateParsedTemplate>(); + auto LPT = std::make_unique<LateParsedTemplate>(); // Take tokens to avoid allocations LPT->Toks.swap(Toks); diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index b55a232d26c2..64ef819e30d4 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -1486,7 +1486,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, #define NON_CANONICAL_TYPE(Class, Base) \ case Type::Class: llvm_unreachable("deducing non-canonical type: " #Class); #define TYPE(Class, Base) -#include "clang/AST/TypeNodes.def" +#include "clang/AST/TypeNodes.inc" case Type::TemplateTypeParm: case Type::SubstTemplateTypeParmPack: @@ -3093,6 +3093,13 @@ Sema::SubstituteExplicitTemplateArguments( Function->getTypeSpecStartLoc(), Function->getDeclName()); if (ResultType.isNull() || Trap.hasErrorOccurred()) return TDK_SubstitutionFailure; + // CUDA: Kernel function must have 'void' return type. + if (getLangOpts().CUDA) + if (Function->hasAttr<CUDAGlobalAttr>() && !ResultType->isVoidType()) { + Diag(Function->getLocation(), diag::err_kern_type_not_void_return) + << Function->getType() << Function->getSourceRange(); + return TDK_SubstitutionFailure; + } } // Instantiate the types of each of the function parameters given the @@ -3702,6 +3709,12 @@ static Sema::TemplateDeductionResult DeduceFromInitializerList( return Sema::TDK_Success; } + // Resolving a core issue: a braced-init-list containing any designators is + // a non-deduced context. + for (Expr *E : ILE->inits()) + if (isa<DesignatedInitExpr>(E)) + return Sema::TDK_Success; + // Deduction only needs to be done for dependent types. if (ElTy->isDependentType()) { for (Expr *E : ILE->inits()) { @@ -3813,8 +3826,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( if (Args.size() < Function->getMinRequiredArguments() && !PartialOverloading) return TDK_TooFewArguments; else if (TooManyArguments(NumParams, Args.size(), PartialOverloading)) { - const FunctionProtoType *Proto - = Function->getType()->getAs<FunctionProtoType>(); + const auto *Proto = Function->getType()->castAs<FunctionProtoType>(); if (Proto->isTemplateVariadic()) /* Do nothing */; else if (!Proto->isVariadic()) @@ -3952,11 +3964,8 @@ QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType, if (ArgFunctionType.isNull()) return ArgFunctionType; - const FunctionProtoType *FunctionTypeP = - FunctionType->castAs<FunctionProtoType>(); - const FunctionProtoType *ArgFunctionTypeP = - ArgFunctionType->getAs<FunctionProtoType>(); - + const auto *FunctionTypeP = FunctionType->castAs<FunctionProtoType>(); + const auto *ArgFunctionTypeP = ArgFunctionType->castAs<FunctionProtoType>(); FunctionProtoType::ExtProtoInfo EPI = ArgFunctionTypeP->getExtProtoInfo(); bool Rebuild = false; @@ -4509,6 +4518,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, if (!Type.getType().getNonReferenceType()->getAs<AutoType>()) return DAR_Failed; + // Resolving a core issue: a braced-init-list containing any designators is + // a non-deduced context. + for (Expr *E : InitList->inits()) + if (isa<DesignatedInitExpr>(E)) + return DAR_Failed; + SourceRange DeducedFromInitRange; for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) { Expr *Init = InitList->getInit(i); @@ -4632,8 +4647,11 @@ bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc, // We might need to deduce the return type by instantiating the definition // of the operator() function. - if (CallOp->getReturnType()->isUndeducedType()) - InstantiateFunctionDefinition(Loc, CallOp); + if (CallOp->getReturnType()->isUndeducedType()) { + runWithSufficientStackSpace(Loc, [&] { + InstantiateFunctionDefinition(Loc, CallOp); + }); + } } if (CallOp->isInvalidDecl()) @@ -4654,8 +4672,11 @@ bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc, return false; } - if (FD->getTemplateInstantiationPattern()) - InstantiateFunctionDefinition(Loc, FD); + if (FD->getTemplateInstantiationPattern()) { + runWithSufficientStackSpace(Loc, [&] { + InstantiateFunctionDefinition(Loc, FD); + }); + } bool StillUndeduced = FD->getReturnType()->isUndeducedType(); if (StillUndeduced && Diagnose && !FD->isInvalidDecl()) { @@ -5590,7 +5611,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, #define ABSTRACT_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) #define NON_CANONICAL_TYPE(Class, Base) case Type::Class: -#include "clang/AST/TypeNodes.def" +#include "clang/AST/TypeNodes.inc" break; } } diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 973f564d3058..0daa33cfbef5 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -19,6 +19,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/PrettyDeclStackTrace.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/Stack.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" @@ -197,12 +198,15 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { case ExplicitTemplateArgumentSubstitution: case DeducedTemplateArgumentSubstitution: case PriorTemplateArgumentSubstitution: + case ConstraintsCheck: return true; case DefaultTemplateArgumentChecking: case DeclaringSpecialMember: case DefiningSynthesizedFunction: case ExceptionSpecEvaluation: + case ConstraintSubstitution: + case RewritingOperatorAsSpaceship: return false; // This function should never be called when Kind's value is Memoization. @@ -357,6 +361,24 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( PointOfInstantiation, InstantiationRange, Param, Template, TemplateArgs) {} +Sema::InstantiatingTemplate::InstantiatingTemplate( + Sema &SemaRef, SourceLocation PointOfInstantiation, + ConstraintsCheck, TemplateDecl *Template, + ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange) + : InstantiatingTemplate( + SemaRef, CodeSynthesisContext::ConstraintsCheck, + PointOfInstantiation, InstantiationRange, Template, nullptr, + TemplateArgs) {} + +Sema::InstantiatingTemplate::InstantiatingTemplate( + Sema &SemaRef, SourceLocation PointOfInstantiation, + ConstraintSubstitution, TemplateDecl *Template, + sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) + : InstantiatingTemplate( + SemaRef, CodeSynthesisContext::ConstraintSubstitution, + PointOfInstantiation, InstantiationRange, Template, nullptr, + {}, &DeductionInfo) {} + void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) { Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext; InNonInstantiationSFINAEContext = false; @@ -365,6 +387,11 @@ void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) { if (!Ctx.isInstantiationRecord()) ++NonInstantiationEntries; + + // Check to see if we're low on stack space. We can't do anything about this + // from here, but we can at least warn the user. + if (isStackNearlyExhausted()) + warnStackExhausted(Ctx.PointOfInstantiation); } void Sema::popCodeSynthesisContext() { @@ -656,8 +683,37 @@ void Sema::PrintInstantiationStack() { break; } + case CodeSynthesisContext::RewritingOperatorAsSpaceship: + Diags.Report(Active->Entity->getLocation(), + diag::note_rewriting_operator_as_spaceship); + break; + 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; + } + // TODO: Concepts - implement this for constrained templates and partial + // specializations. + llvm_unreachable("only concept constraints are supported right now"); + break; + + case CodeSynthesisContext::ConstraintSubstitution: + Diags.Report(Active->PointOfInstantiation, + diag::note_constraint_substitution_here) + << Active->InstantiationRange; + break; } } } @@ -681,6 +737,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { LLVM_FALLTHROUGH; case CodeSynthesisContext::DefaultFunctionArgumentInstantiation: case CodeSynthesisContext::ExceptionSpecInstantiation: + case CodeSynthesisContext::ConstraintsCheck: // This is a template instantiation, so there is no SFINAE. return None; @@ -694,13 +751,16 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution: case CodeSynthesisContext::DeducedTemplateArgumentSubstitution: - // We're either substitution explicitly-specified template arguments - // or deduced template arguments, so SFINAE applies. + case CodeSynthesisContext::ConstraintSubstitution: + // We're either substituting explicitly-specified template arguments + // or deduced template arguments or a constraint expression, so SFINAE + // applies. assert(Active->DeductionInfo && "Missing deduction info pointer"); return Active->DeductionInfo; case CodeSynthesisContext::DeclaringSpecialMember: case CodeSynthesisContext::DefiningSynthesizedFunction: + case CodeSynthesisContext::RewritingOperatorAsSpaceship: // This happens in a context unrelated to template instantiation, so // there is no SFINAE. return None; @@ -1252,9 +1312,8 @@ TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) { // Create new LoopHintValueAttr with integral expression in place of the // non-type template parameter. - return LoopHintAttr::CreateImplicit( - getSema().Context, LH->getSemanticSpelling(), LH->getOption(), - LH->getState(), TransformedExpr, LH->getRange()); + return LoopHintAttr::CreateImplicit(getSema().Context, LH->getOption(), + LH->getState(), TransformedExpr, *LH); } ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef( diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 67343d11d333..d1ad304e62e4 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -86,15 +86,13 @@ static void instantiateDependentAlignedAttr( S, Sema::ExpressionEvaluationContext::ConstantEvaluated); ExprResult Result = S.SubstExpr(Aligned->getAlignmentExpr(), TemplateArgs); if (!Result.isInvalid()) - S.AddAlignedAttr(Aligned->getLocation(), New, Result.getAs<Expr>(), - Aligned->getSpellingListIndex(), IsPackExpansion); + S.AddAlignedAttr(New, *Aligned, Result.getAs<Expr>(), IsPackExpansion); } else { TypeSourceInfo *Result = S.SubstType(Aligned->getAlignmentType(), TemplateArgs, Aligned->getLocation(), DeclarationName()); if (Result) - S.AddAlignedAttr(Aligned->getLocation(), New, Result, - Aligned->getSpellingListIndex(), IsPackExpansion); + S.AddAlignedAttr(New, *Aligned, Result, IsPackExpansion); } } @@ -156,8 +154,7 @@ static void instantiateDependentAssumeAlignedAttr( OE = Result.getAs<Expr>(); } - S.AddAssumeAlignedAttr(Aligned->getLocation(), New, E, OE, - Aligned->getSpellingListIndex()); + S.AddAssumeAlignedAttr(New, *Aligned, E, OE); } static void instantiateDependentAlignValueAttr( @@ -168,8 +165,7 @@ static void instantiateDependentAlignValueAttr( S, Sema::ExpressionEvaluationContext::ConstantEvaluated); ExprResult Result = S.SubstExpr(Aligned->getAlignment(), TemplateArgs); if (!Result.isInvalid()) - S.AddAlignValueAttr(Aligned->getLocation(), New, Result.getAs<Expr>(), - Aligned->getSpellingListIndex()); + S.AddAlignValueAttr(New, *Aligned, Result.getAs<Expr>()); } static void instantiateDependentAllocAlignAttr( @@ -179,8 +175,7 @@ static void instantiateDependentAllocAlignAttr( S.getASTContext(), llvm::APInt(64, Align->getParamIndex().getSourceIndex()), S.getASTContext().UnsignedLongLongTy, Align->getLocation()); - S.AddAllocAlignAttr(Align->getLocation(), New, Param, - Align->getSpellingListIndex()); + S.AddAllocAlignAttr(New, *Align, Param); } static Expr *instantiateDependentFunctionAttrCondition( @@ -221,9 +216,8 @@ static void instantiateDependentEnableIfAttr( S, TemplateArgs, EIA, EIA->getCond(), Tmpl, New); if (Cond) - New->addAttr(new (S.getASTContext()) EnableIfAttr( - EIA->getLocation(), S.getASTContext(), Cond, EIA->getMessage(), - EIA->getSpellingListIndex())); + New->addAttr(new (S.getASTContext()) EnableIfAttr(S.getASTContext(), *EIA, + Cond, EIA->getMessage())); } static void instantiateDependentDiagnoseIfAttr( @@ -234,9 +228,8 @@ static void instantiateDependentDiagnoseIfAttr( if (Cond) New->addAttr(new (S.getASTContext()) DiagnoseIfAttr( - DIA->getLocation(), S.getASTContext(), Cond, DIA->getMessage(), - DIA->getDiagnosticType(), DIA->getArgDependent(), New, - DIA->getSpellingListIndex())); + S.getASTContext(), *DIA, Cond, DIA->getMessage(), + DIA->getDiagnosticType(), DIA->getArgDependent(), New)); } // Constructs and adds to New a new instance of CUDALaunchBoundsAttr using @@ -261,16 +254,15 @@ static void instantiateDependentCUDALaunchBoundsAttr( MinBlocks = Result.getAs<Expr>(); } - S.AddLaunchBoundsAttr(Attr.getLocation(), New, MaxThreads, MinBlocks, - Attr.getSpellingListIndex()); + S.AddLaunchBoundsAttr(New, Attr, MaxThreads, MinBlocks); } static void instantiateDependentModeAttr(Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, const ModeAttr &Attr, Decl *New) { - S.AddModeAttr(Attr.getRange(), New, Attr.getMode(), - Attr.getSpellingListIndex(), /*InInstantiation=*/true); + S.AddModeAttr(New, Attr, Attr.getMode(), + /*InInstantiation=*/true); } /// Instantiation of 'declare simd' attribute and its arguments. @@ -356,6 +348,67 @@ static void instantiateOMPDeclareSimdDeclAttr( Attr.getRange()); } +/// Instantiation of 'declare variant' attribute and its arguments. +static void instantiateOMPDeclareVariantAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const OMPDeclareVariantAttr &Attr, Decl *New) { + // Allow 'this' in clauses with varlists. + if (auto *FTD = dyn_cast<FunctionTemplateDecl>(New)) + New = FTD->getTemplatedDecl(); + auto *FD = cast<FunctionDecl>(New); + auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(FD->getDeclContext()); + + auto &&SubstExpr = [FD, ThisContext, &S, &TemplateArgs](Expr *E) { + if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) + if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) { + Sema::ContextRAII SavedContext(S, FD); + LocalInstantiationScope Local(S); + if (FD->getNumParams() > PVD->getFunctionScopeIndex()) + Local.InstantiatedLocal( + PVD, FD->getParamDecl(PVD->getFunctionScopeIndex())); + return S.SubstExpr(E, TemplateArgs); + } + Sema::CXXThisScopeRAII ThisScope(S, ThisContext, Qualifiers(), + FD->isCXXInstanceMember()); + return S.SubstExpr(E, TemplateArgs); + }; + + // Substitute a single OpenMP clause, which is a potentially-evaluated + // full-expression. + auto &&Subst = [&SubstExpr, &S](Expr *E) { + EnterExpressionEvaluationContext Evaluated( + S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated); + ExprResult Res = SubstExpr(E); + if (Res.isInvalid()) + return Res; + return S.ActOnFinishFullExpr(Res.get(), false); + }; + + ExprResult VariantFuncRef; + if (Expr *E = Attr.getVariantFuncRef()) + VariantFuncRef = Subst(E); + + ExprResult Score; + if (Expr *E = Attr.getScore()) + Score = Subst(E); + + // Check function/variant ref. + Optional<std::pair<FunctionDecl *, Expr *>> DeclVarData = + S.checkOpenMPDeclareVariantFunction( + 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); + S.ActOnOpenMPDeclareVariantDirective(DeclVarData.getValue().first, + DeclVarData.getValue().second, + Attr.getRange(), Data); +} + static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr( Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, const AMDGPUFlatWorkGroupSizeAttr &Attr, Decl *New) { @@ -373,8 +426,7 @@ static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr( return; Expr *MaxExpr = Result.getAs<Expr>(); - S.addAMDGPUFlatWorkGroupSizeAttr(Attr.getLocation(), New, MinExpr, MaxExpr, - Attr.getSpellingListIndex()); + S.addAMDGPUFlatWorkGroupSizeAttr(New, Attr, MinExpr, MaxExpr); } static ExplicitSpecifier @@ -420,8 +472,7 @@ static void instantiateDependentAMDGPUWavesPerEUAttr( MaxExpr = Result.getAs<Expr>(); } - S.addAMDGPUWavesPerEUAttr(Attr.getLocation(), New, MinExpr, MaxExpr, - Attr.getSpellingListIndex()); + S.addAMDGPUWavesPerEUAttr(New, Attr, MinExpr, MaxExpr); } void Sema::InstantiateAttrsForDecl( @@ -470,14 +521,12 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, continue; } - const AssumeAlignedAttr *AssumeAligned = dyn_cast<AssumeAlignedAttr>(TmplAttr); - if (AssumeAligned) { + if (const auto *AssumeAligned = dyn_cast<AssumeAlignedAttr>(TmplAttr)) { instantiateDependentAssumeAlignedAttr(*this, TemplateArgs, AssumeAligned, New); continue; } - const AlignValueAttr *AlignValue = dyn_cast<AlignValueAttr>(TmplAttr); - if (AlignValue) { + if (const auto *AlignValue = dyn_cast<AlignValueAttr>(TmplAttr)) { instantiateDependentAlignValueAttr(*this, TemplateArgs, AlignValue, New); continue; } @@ -500,14 +549,14 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, continue; } - if (const CUDALaunchBoundsAttr *CUDALaunchBounds = + if (const auto *CUDALaunchBounds = dyn_cast<CUDALaunchBoundsAttr>(TmplAttr)) { instantiateDependentCUDALaunchBoundsAttr(*this, TemplateArgs, *CUDALaunchBounds, New); continue; } - if (const ModeAttr *Mode = dyn_cast<ModeAttr>(TmplAttr)) { + if (const auto *Mode = dyn_cast<ModeAttr>(TmplAttr)) { instantiateDependentModeAttr(*this, TemplateArgs, *Mode, New); continue; } @@ -517,13 +566,18 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, continue; } - if (const AMDGPUFlatWorkGroupSizeAttr *AMDGPUFlatWorkGroupSize = + if (const auto *OMPAttr = dyn_cast<OMPDeclareVariantAttr>(TmplAttr)) { + instantiateOMPDeclareVariantAttr(*this, TemplateArgs, *OMPAttr, New); + continue; + } + + if (const auto *AMDGPUFlatWorkGroupSize = dyn_cast<AMDGPUFlatWorkGroupSizeAttr>(TmplAttr)) { instantiateDependentAMDGPUFlatWorkGroupSizeAttr( *this, TemplateArgs, *AMDGPUFlatWorkGroupSize, New); } - if (const AMDGPUWavesPerEUAttr *AMDGPUFlatWorkGroupSize = + if (const auto *AMDGPUFlatWorkGroupSize = dyn_cast<AMDGPUWavesPerEUAttr>(TmplAttr)) { instantiateDependentAMDGPUWavesPerEUAttr(*this, TemplateArgs, *AMDGPUFlatWorkGroupSize, New); @@ -537,21 +591,30 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, } } - if (auto ABIAttr = dyn_cast<ParameterABIAttr>(TmplAttr)) { - AddParameterABIAttr(ABIAttr->getRange(), New, ABIAttr->getABI(), - ABIAttr->getSpellingListIndex()); + if (const auto *ABIAttr = dyn_cast<ParameterABIAttr>(TmplAttr)) { + AddParameterABIAttr(New, *ABIAttr, ABIAttr->getABI()); continue; } if (isa<NSConsumedAttr>(TmplAttr) || isa<OSConsumedAttr>(TmplAttr) || isa<CFConsumedAttr>(TmplAttr)) { - AddXConsumedAttr(New, TmplAttr->getRange(), - TmplAttr->getSpellingListIndex(), - attrToRetainOwnershipKind(TmplAttr), + AddXConsumedAttr(New, *TmplAttr, attrToRetainOwnershipKind(TmplAttr), /*template instantiation=*/true); continue; } + if (auto *A = dyn_cast<PointerAttr>(TmplAttr)) { + if (!New->hasAttr<PointerAttr>()) + New->addAttr(A->clone(Context)); + continue; + } + + if (auto *A = dyn_cast<OwnerAttr>(TmplAttr)) { + if (!New->hasAttr<OwnerAttr>()) + New->addAttr(A->clone(Context)); + continue; + } + assert(!TmplAttr->isPackExpansion()); if (TmplAttr->isLateParsed() && LateAttrs) { // Late parsed attributes must be instantiated and attached after the @@ -711,6 +774,9 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D, SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef); + if (D->getUnderlyingType()->getAs<DependentNameType>()) + SemaRef.inferGslPointerAttribute(Typedef); + Typedef->setAccess(D->getAccess()); return Typedef; @@ -2090,10 +2156,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( Constructor->getConstexprKind()); 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); + Method = CXXDestructorDecl::Create( + SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, + Destructor->isInlineSpecified(), false, Destructor->getConstexprKind()); Method->setRangeEnd(Destructor->getEndLoc()); } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) { Method = CXXConversionDecl::Create( @@ -2339,6 +2404,7 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getIndex(), D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack()); Inst->setAccess(AS_public); + Inst->setImplicit(D->isImplicit()); if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { TypeSourceInfo *InstantiatedDefaultArg = @@ -2485,6 +2551,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI); Param->setAccess(AS_public); + Param->setImplicit(D->isImplicit()); if (Invalid) Param->setInvalidDecl(); @@ -2628,6 +2695,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl( D->getDefaultArgument().getTemplateNameLoc())); } Param->setAccess(AS_public); + Param->setImplicit(D->isImplicit()); // Introduce this template parameter's instantiation into the instantiation // scope. @@ -3415,7 +3483,11 @@ Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner, if (D->isInvalidDecl()) return nullptr; - return Instantiator.Visit(D); + Decl *SubstD; + runWithSufficientStackSpace(D->getLocation(), [&] { + SubstD = Instantiator.Visit(D); + }); + return SubstD; } /// Instantiates a nested template parameter list in the current @@ -3443,14 +3515,21 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { if (Invalid) return nullptr; - // Note: we substitute into associated constraints later - Expr *const UninstantiatedRequiresClause = L->getRequiresClause(); + // FIXME: Concepts: Substitution into requires clause should only happen when + // checking satisfaction. + Expr *InstRequiresClause = nullptr; + if (Expr *E = L->getRequiresClause()) { + ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs); + if (Res.isInvalid() || !Res.isUsable()) { + return nullptr; + } + InstRequiresClause = Res.get(); + } TemplateParameterList *InstL = TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(), L->getLAngleLoc(), Params, - L->getRAngleLoc(), - UninstantiatedRequiresClause); + L->getRAngleLoc(), InstRequiresClause); return InstL; } @@ -5217,11 +5296,11 @@ DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC, /// template struct X<int>; /// \endcode /// -/// In the instantiation of <tt>X<int>::getKind()</tt>, we need to map the -/// \p EnumConstantDecl for \p KnownValue (which refers to -/// <tt>X<T>::<Kind>::KnownValue</tt>) to its instantiation -/// (<tt>X<int>::<Kind>::KnownValue</tt>). \p FindInstantiatedDecl performs -/// this mapping from within the instantiation of <tt>X<int></tt>. +/// In the instantiation of X<int>::getKind(), we need to map the \p +/// EnumConstantDecl for \p KnownValue (which refers to +/// X<T>::<Kind>::KnownValue) to its instantiation (X<int>::<Kind>::KnownValue). +/// \p FindInstantiatedDecl performs this mapping from within the instantiation +/// of X<int>. NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs, bool FindingInstantiatedContext) { @@ -5312,20 +5391,6 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, return cast<LabelDecl>(Inst); } - // For variable template specializations, update those that are still - // type-dependent. - if (VarTemplateSpecializationDecl *VarSpec = - dyn_cast<VarTemplateSpecializationDecl>(D)) { - bool InstantiationDependent = false; - const TemplateArgumentListInfo &VarTemplateArgs = - VarSpec->getTemplateArgsInfo(); - if (TemplateSpecializationType::anyDependentTemplateArguments( - VarTemplateArgs, InstantiationDependent)) - D = cast<NamedDecl>( - SubstDecl(D, VarSpec->getDeclContext(), TemplateArgs)); - return D; - } - if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) { if (!Record->isDependentContext()) return D; @@ -5450,11 +5515,23 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // find it. Does that ever matter? if (auto Name = D->getDeclName()) { DeclarationNameInfo NameInfo(Name, D->getLocation()); - Name = SubstDeclarationNameInfo(NameInfo, TemplateArgs).getName(); + DeclarationNameInfo NewNameInfo = + SubstDeclarationNameInfo(NameInfo, TemplateArgs); + Name = NewNameInfo.getName(); if (!Name) return nullptr; DeclContext::lookup_result Found = ParentDC->lookup(Name); - Result = findInstantiationOf(Context, D, Found.begin(), Found.end()); + + if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) { + VarTemplateDecl *Templ = cast_or_null<VarTemplateDecl>( + findInstantiationOf(Context, VTSD->getSpecializedTemplate(), + Found.begin(), Found.end())); + if (!Templ) + return nullptr; + Result = getVarTemplateSpecialization( + Templ, &VTSD->getTemplateArgsInfo(), NewNameInfo, SourceLocation()); + } else + Result = findInstantiationOf(Context, D, Found.begin(), Found.end()); } else { // Since we don't have a name for the entity we're looking for, // our only option is to walk through all of the declarations to diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index d97626551a41..975d6620c06f 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -294,44 +294,58 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, return false; // If we are within a lambda expression and referencing a pack that is not - // a parameter of the lambda itself, that lambda contains an unexpanded + // declared within the lambda itself, that lambda contains an unexpanded // parameter pack, and we are done. // FIXME: Store 'Unexpanded' on the lambda so we don't need to recompute it // later. SmallVector<UnexpandedParameterPack, 4> LambdaParamPackReferences; - for (unsigned N = FunctionScopes.size(); N; --N) { - sema::FunctionScopeInfo *Func = FunctionScopes[N-1]; - // We do not permit pack expansion that would duplicate a statement - // expression, not even within a lambda. - // FIXME: We could probably support this for statement expressions that do - // not contain labels, and for pack expansions that expand both the stmt - // expr and the enclosing lambda. - if (std::any_of( - Func->CompoundScopes.begin(), Func->CompoundScopes.end(), - [](sema::CompoundScopeInfo &CSI) { return CSI.IsStmtExpr; })) - break; + if (auto *LSI = getEnclosingLambda()) { + for (auto &Pack : Unexpanded) { + auto DeclaresThisPack = [&](NamedDecl *LocalPack) { + if (auto *TTPT = Pack.first.dyn_cast<const TemplateTypeParmType *>()) { + auto *TTPD = dyn_cast<TemplateTypeParmDecl>(LocalPack); + return TTPD && TTPD->getTypeForDecl() == TTPT; + } + return declaresSameEntity(Pack.first.get<NamedDecl *>(), LocalPack); + }; + if (std::find_if(LSI->LocalPacks.begin(), LSI->LocalPacks.end(), + DeclaresThisPack) != LSI->LocalPacks.end()) + LambdaParamPackReferences.push_back(Pack); + } - if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Func)) { - if (N == FunctionScopes.size()) { - for (auto &Pack : Unexpanded) { - auto *VD = dyn_cast_or_null<VarDecl>( - Pack.first.dyn_cast<NamedDecl *>()); - if (VD && VD->getDeclContext() == LSI->CallOperator) - LambdaParamPackReferences.push_back(Pack); + if (LambdaParamPackReferences.empty()) { + // Construct in lambda only references packs declared outside the lambda. + // That's OK for now, but the lambda itself is considered to contain an + // unexpanded pack in this case, which will require expansion outside the + // lambda. + + // We do not permit pack expansion that would duplicate a statement + // expression, not even within a lambda. + // FIXME: We could probably support this for statement expressions that + // do not contain labels. + // FIXME: This is insufficient to detect this problem; consider + // f( ({ bad: 0; }) + pack ... ); + bool EnclosingStmtExpr = false; + for (unsigned N = FunctionScopes.size(); N; --N) { + sema::FunctionScopeInfo *Func = FunctionScopes[N-1]; + if (std::any_of( + Func->CompoundScopes.begin(), Func->CompoundScopes.end(), + [](sema::CompoundScopeInfo &CSI) { return CSI.IsStmtExpr; })) { + EnclosingStmtExpr = true; + break; } + // Coumpound-statements outside the lambda are OK for now; we'll check + // for those when we finish handling the lambda. + if (Func == LSI) + break; } - // If we have references to a parameter pack of the innermost enclosing - // lambda, only diagnose those ones. We don't know whether any other - // unexpanded parameters referenced herein are actually unexpanded; - // they might be expanded at an outer level. - if (!LambdaParamPackReferences.empty()) { - Unexpanded = LambdaParamPackReferences; - break; + if (!EnclosingStmtExpr) { + LSI->ContainsUnexpandedParameterPack = true; + return false; } - - LSI->ContainsUnexpandedParameterPack = true; - return false; + } else { + Unexpanded = LambdaParamPackReferences; } } @@ -937,7 +951,7 @@ class ParameterPackValidatorCCC final : public CorrectionCandidateCallback { } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<ParameterPackValidatorCCC>(*this); + return std::make_unique<ParameterPackValidatorCCC>(*this); } }; diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 29acf6177eb9..fccdb2bc2e2c 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -82,7 +82,7 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr, } SourceLocation loc = attr.getLoc(); - StringRef name = attr.getName()->getName(); + StringRef name = attr.getAttrName()->getName(); // The GC attributes are usually written with macros; special-case them. IdentifierInfo *II = attr.isArgIdent(0) ? attr.getArgAsIdent(0)->Ident @@ -811,7 +811,7 @@ static bool checkOmittedBlockReturnType(Sema &S, Declarator &declarator, continue; S.Diag(AL.getLoc(), diag::warn_block_literal_attributes_on_omitted_return_type) - << AL.getName(); + << AL; ToBeRemoved.push_back(&AL); } // Remove bad attributes from the list. @@ -1290,14 +1290,14 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified) Result = Context.WCharTy; else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) { - S.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) + S.Diag(DS.getTypeSpecSignLoc(), diag::ext_wchar_t_sign_spec) << DS.getSpecifierName(DS.getTypeSpecType(), Context.getPrintingPolicy()); Result = Context.getSignedWCharType(); } else { assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned && "Unknown TSS value"); - S.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) + S.Diag(DS.getTypeSpecSignLoc(), diag::ext_wchar_t_sign_spec) << DS.getSpecifierName(DS.getTypeSpecType(), Context.getPrintingPolicy()); Result = Context.getUnsignedWCharType(); @@ -1633,6 +1633,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { case OpenCLAccessAttr::Keyword_read_only: \ Result = Context.Id##ROTy; \ break; \ + case OpenCLAccessAttr::SpellingNotCalculated: \ + llvm_unreachable("Spelling not yet calculated"); \ } \ break; #include "clang/Basic/OpenCLImageTypes.def" @@ -1953,7 +1955,8 @@ static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation Loc, QualifiedFunctionKind QFK) { // Does T refer to a function type with a cv-qualifier or a ref-qualifier? const FunctionProtoType *FPT = T->getAs<FunctionProtoType>(); - if (!FPT || (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None)) + if (!FPT || + (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None)) return false; S.Diag(Loc, diag::err_compound_qualified_function_type) @@ -1962,6 +1965,17 @@ static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation Loc, return true; } +bool Sema::CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc) { + const FunctionProtoType *FPT = T->getAs<FunctionProtoType>(); + if (!FPT || + (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None)) + return false; + + Diag(Loc, diag::err_qualified_function_typeid) + << T << getFunctionQualifiersAsString(FPT); + return true; +} + /// Build a pointer type. /// /// \param T The type to which we'll be building a pointer. @@ -2276,7 +2290,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, } } - T = Context.getConstantArrayType(T, ConstVal, ASM, Quals); + T = Context.getConstantArrayType(T, ConstVal, ArraySize, ASM, Quals); } // OpenCL v1.2 s6.9.d: variable length arrays are not supported. @@ -2461,6 +2475,11 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) { checkNonTrivialCUnion(T, Loc, NTCUC_FunctionReturn, NTCUK_Destruct|NTCUK_Copy); + // C++2a [dcl.fct]p12: + // A volatile-qualified return type is deprecated + if (T.isVolatileQualified() && getLangOpts().CPlusPlus2a) + Diag(Loc, diag::warn_deprecated_volatile_return) << T; + return false; } @@ -2541,6 +2560,11 @@ QualType Sema::BuildFunctionType(QualType T, Invalid = true; } + // C++2a [dcl.fct]p4: + // A parameter with volatile-qualified type is deprecated + if (ParamType.isVolatileQualified() && getLangOpts().CPlusPlus2a) + Diag(Loc, diag::warn_deprecated_volatile_param) << ParamType; + ParamTypes[Idx] = ParamType; } @@ -3942,10 +3966,9 @@ static bool IsNoDerefableChunk(DeclaratorChunk Chunk) { } template<typename AttrT> -static AttrT *createSimpleAttr(ASTContext &Ctx, ParsedAttr &Attr) { - Attr.setUsedAsTypeAttr(); - return ::new (Ctx) - AttrT(Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex()); +static AttrT *createSimpleAttr(ASTContext &Ctx, ParsedAttr &AL) { + AL.setUsedAsTypeAttr(); + return ::new (Ctx) AttrT(Ctx, AL); } static Attr *createNullabilityAttr(ASTContext &Ctx, ParsedAttr &Attr, @@ -4672,6 +4695,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, S.Diag(DeclType.Loc, diag::err_func_returning_qualified_void) << T; } else diagnoseRedundantReturnTypeQualifiers(S, T, D, chunkIndex); + + // C++2a [dcl.fct]p12: + // A volatile-qualified return type is deprecated + if (T.isVolatileQualified() && S.getLangOpts().CPlusPlus2a) + S.Diag(DeclType.Loc, diag::warn_deprecated_volatile_return) << T; } // Objective-C ARC ownership qualifiers are ignored on the function @@ -5151,9 +5179,16 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // C++0x [dcl.constexpr]p9: // A constexpr specifier used in an object declaration declares the object // as const. - if (D.getDeclSpec().hasConstexprSpecifier() && T->isObjectType()) { + if (D.getDeclSpec().getConstexprSpecifier() == CSK_constexpr && + T->isObjectType()) T.addConst(); - } + + // C++2a [dcl.fct]p4: + // A parameter with volatile-qualified type is deprecated + if (T.isVolatileQualified() && S.getLangOpts().CPlusPlus2a && + (D.getContext() == DeclaratorContext::PrototypeContext || + D.getContext() == DeclaratorContext::LambdaExprParameterContext)) + S.Diag(D.getIdentifierLoc(), diag::warn_deprecated_volatile_param) << T; // If there was an ellipsis in the declarator, the declaration declares a // parameter pack whose type may be a pack expansion type. @@ -5983,9 +6018,8 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, } ASTContext &Ctx = S.Context; - auto *ASAttr = ::new (Ctx) AddressSpaceAttr( - Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex(), - static_cast<unsigned>(ASIdx)); + auto *ASAttr = + ::new (Ctx) AddressSpaceAttr(Ctx, Attr, static_cast<unsigned>(ASIdx)); // If the expression is not value dependent (not templated), then we can // apply the address space qualifiers just to the equivalent type. @@ -6027,36 +6061,6 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, } } -/// Does this type have a "direct" ownership qualifier? That is, -/// is it written like "__strong id", as opposed to something like -/// "typeof(foo)", where that happens to be strong? -static bool hasDirectOwnershipQualifier(QualType type) { - // Fast path: no qualifier at all. - assert(type.getQualifiers().hasObjCLifetime()); - - while (true) { - // __strong id - if (const AttributedType *attr = dyn_cast<AttributedType>(type)) { - if (attr->getAttrKind() == attr::ObjCOwnership) - return true; - - type = attr->getModifiedType(); - - // X *__strong (...) - } else if (const ParenType *paren = dyn_cast<ParenType>(type)) { - type = paren->getInnerType(); - - // That's it for things we want to complain about. In particular, - // we do not want to look through typedefs, typeof(expr), - // typeof(type), or any other way that the type is somehow - // abstracted. - } else { - - return false; - } - } -} - /// handleObjCOwnershipTypeAttr - Process an objc_ownership /// attribute on the specified type. /// @@ -6112,8 +6116,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, else if (II->isStr("autoreleasing")) lifetime = Qualifiers::OCL_Autoreleasing; else { - S.Diag(AttrLoc, diag::warn_attribute_type_not_supported) - << attr.getName() << II; + S.Diag(AttrLoc, diag::warn_attribute_type_not_supported) << attr << II; attr.setInvalid(); return true; } @@ -6132,7 +6135,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, if (Qualifiers::ObjCLifetime previousLifetime = type.getQualifiers().getObjCLifetime()) { // If it's written directly, that's an error. - if (hasDirectOwnershipQualifier(type)) { + if (S.Context.hasDirectOwnershipQualifier(type)) { S.Diag(AttrLoc, diag::err_attr_objc_ownership_redundant) << type; return true; @@ -6155,7 +6158,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, underlyingType.Quals.addObjCLifetime(lifetime); if (NonObjCPointer) { - StringRef name = attr.getName()->getName(); + StringRef name = attr.getAttrName()->getName(); switch (lifetime) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: @@ -6194,9 +6197,8 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, // If we have a valid source location for the attribute, use an // AttributedType instead. if (AttrLoc.isValid()) { - type = state.getAttributedType(::new (S.Context) ObjCOwnershipAttr( - attr.getRange(), S.Context, II, - attr.getAttributeSpellingListIndex()), + type = state.getAttributedType(::new (S.Context) + ObjCOwnershipAttr(S.Context, attr, II), origType, type); } @@ -6288,7 +6290,7 @@ static bool handleObjCGCTypeAttr(TypeProcessingState &state, ParsedAttr &attr, GCAttr = Qualifiers::Strong; else { S.Diag(attr.getLoc(), diag::warn_attribute_type_not_supported) - << attr.getName() << II; + << attr << II; attr.setInvalid(); return true; } @@ -6299,9 +6301,7 @@ static bool handleObjCGCTypeAttr(TypeProcessingState &state, ParsedAttr &attr, // Make an attributed type to preserve the source information. if (attr.getLoc().isValid()) type = state.getAttributedType( - ::new (S.Context) ObjCGCAttr(attr.getRange(), S.Context, II, - attr.getAttributeSpellingListIndex()), - origType, type); + ::new (S.Context) ObjCGCAttr(S.Context, attr, II), origType, type); return true; } @@ -6473,8 +6473,7 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, // 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.getName(); + S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr; return true; } @@ -6743,9 +6742,9 @@ static bool distributeNullabilityTypeAttr(TypeProcessingState &state, if (chunk.Kind != DeclaratorChunk::MemberPointer) { diag << FixItHint::CreateRemoval(attr.getLoc()) << FixItHint::CreateInsertion( - state.getSema().getPreprocessor() - .getLocForEndOfToken(chunk.Loc), - " " + attr.getName()->getName().str() + " "); + state.getSema().getPreprocessor().getLocForEndOfToken( + chunk.Loc), + " " + attr.getAttrName()->getName().str() + " "); } moveAttrFromListToList(attr, state.getCurrentAttributes(), @@ -6823,8 +6822,7 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) { PcsAttr::PCSType Type; if (!PcsAttr::ConvertStrToPCSType(Str, Type)) llvm_unreachable("already validated the attribute"); - return ::new (Ctx) PcsAttr(Attr.getRange(), Ctx, Type, - Attr.getAttributeSpellingListIndex()); + return ::new (Ctx) PcsAttr(Ctx, Attr, Type); } case ParsedAttr::AT_IntelOclBicc: return createSimpleAttr<IntelOclBiccAttr>(Ctx, Attr); @@ -7343,7 +7341,7 @@ static void HandleOpenCLAccessAttr(QualType &CurType, const ParsedAttr &Attr, } else { llvm_unreachable("unexpected type"); } - StringRef AttrName = Attr.getName()->getName(); + StringRef AttrName = Attr.getAttrName()->getName(); if (PrevAccessQual == AttrName.ltrim("_")) { // Duplicated qualifiers S.Diag(Attr.getLoc(), diag::warn_duplicate_declspec) @@ -7390,8 +7388,22 @@ static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State, bool IsPointee = ChunkIndex > 0 && (D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Pointer || - D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::BlockPointer || - D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Reference); + 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; @@ -7526,7 +7538,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, IsTypeAttr ? diag::warn_gcc_ignores_type_attr : diag::warn_cxx11_gnu_attribute_on_type) - << attr.getName(); + << attr; if (!IsTypeAttr) continue; } @@ -7555,7 +7567,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, if (attr.isCXX11Attribute() && TAL == TAL_DeclChunk) state.getSema().Diag(attr.getLoc(), diag::warn_unknown_attribute_ignored) - << attr.getName(); + << attr; break; case ParsedAttr::IgnoredAttribute: @@ -7720,7 +7732,9 @@ void Sema::completeExprArrayBound(Expr *E) { auto *Def = Var->getDefinition(); if (!Def) { SourceLocation PointOfInstantiation = E->getExprLoc(); - InstantiateVariableDefinition(PointOfInstantiation, Var); + runWithSufficientStackSpace(PointOfInstantiation, [&] { + InstantiateVariableDefinition(PointOfInstantiation, Var); + }); Def = Var->getDefinition(); // If we don't already have a point of instantiation, and we managed @@ -7947,14 +7961,16 @@ static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) { break; } - RD->addAttr(MSInheritanceAttr::CreateImplicit( - S.getASTContext(), IM, - /*BestCase=*/S.MSPointerToMemberRepresentationMethod == - LangOptions::PPTMK_BestCase, - S.ImplicitMSInheritanceAttrLoc.isValid() - ? S.ImplicitMSInheritanceAttrLoc - : RD->getSourceRange())); - S.Consumer.AssignInheritanceModel(RD); + 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); } } @@ -8058,9 +8074,11 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, } else if (auto *ClassTemplateSpec = dyn_cast<ClassTemplateSpecializationDecl>(RD)) { if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) { - Diagnosed = InstantiateClassTemplateSpecialization( - Loc, ClassTemplateSpec, TSK_ImplicitInstantiation, - /*Complain=*/Diagnoser); + runWithSufficientStackSpace(Loc, [&] { + Diagnosed = InstantiateClassTemplateSpecialization( + Loc, ClassTemplateSpec, TSK_ImplicitInstantiation, + /*Complain=*/Diagnoser); + }); Instantiated = true; } } else { @@ -8071,10 +8089,12 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // This record was instantiated from a class within a template. if (MSI->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) { - Diagnosed = InstantiateClass(Loc, RD, Pattern, - getTemplateInstantiationArgs(RD), - TSK_ImplicitInstantiation, - /*Complain=*/Diagnoser); + runWithSufficientStackSpace(Loc, [&] { + Diagnosed = InstantiateClass(Loc, RD, Pattern, + getTemplateInstantiationArgs(RD), + TSK_ImplicitInstantiation, + /*Complain=*/Diagnoser); + }); Instantiated = true; } } @@ -8222,20 +8242,28 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, return true; } } - } else if (!RD->hasTrivialDestructor()) { - // All fields and bases are of literal types, so have trivial destructors. - // If this class's destructor is non-trivial it must be user-declared. + } else if (getLangOpts().CPlusPlus2a ? !RD->hasConstexprDestructor() + : !RD->hasTrivialDestructor()) { + // All fields and bases are of literal types, so have trivial or constexpr + // destructors. If this class's destructor is non-trivial / non-constexpr, + // it must be user-declared. CXXDestructorDecl *Dtor = RD->getDestructor(); assert(Dtor && "class has literal fields and bases but no dtor?"); if (!Dtor) return true; - Diag(Dtor->getLocation(), Dtor->isUserProvided() ? - diag::note_non_literal_user_provided_dtor : - diag::note_non_literal_nontrivial_dtor) << RD; - if (!Dtor->isUserProvided()) - SpecialMemberIsTrivial(Dtor, CXXDestructor, TAH_IgnoreTrivialABI, - /*Diagnose*/true); + if (getLangOpts().CPlusPlus2a) { + Diag(Dtor->getLocation(), diag::note_non_literal_non_constexpr_dtor) + << RD; + } else { + Diag(Dtor->getLocation(), Dtor->isUserProvided() + ? diag::note_non_literal_user_provided_dtor + : diag::note_non_literal_nontrivial_dtor) + << RD; + if (!Dtor->isUserProvided()) + SpecialMemberIsTrivial(Dtor, CXXDestructor, TAH_IgnoreTrivialABI, + /*Diagnose*/ true); + } } return true; diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 8df18b5c2784..4b3a6708717c 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -795,6 +795,7 @@ public: QualType RebuildConstantArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, const llvm::APInt &Size, + Expr *SizeExpr, unsigned IndexTypeQuals, SourceRange BracketsRange); @@ -2167,13 +2168,12 @@ public: ExprResult RebuildDeclRefExpr(NestedNameSpecifierLoc QualifierLoc, ValueDecl *VD, const DeclarationNameInfo &NameInfo, + NamedDecl *Found, TemplateArgumentListInfo *TemplateArgs) { CXXScopeSpec SS; SS.Adopt(QualifierLoc); - - // FIXME: loses template args. - - return getSema().BuildDeclarationNameExpr(SS, NameInfo, VD); + return getSema().BuildDeclarationNameExpr(SS, NameInfo, VD, Found, + TemplateArgs); } /// Build a new expression in parentheses. @@ -2353,6 +2353,17 @@ public: return getSema().BuildBinOp(/*Scope=*/nullptr, OpLoc, Opc, LHS, RHS); } + /// Build a new rewritten operator expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildCXXRewrittenBinaryOperator( + SourceLocation OpLoc, BinaryOperatorKind Opcode, + const UnresolvedSetImpl &UnqualLookups, Expr *LHS, Expr *RHS) { + return getSema().CreateOverloadedBinOp(OpLoc, Opcode, UnqualLookups, LHS, + RHS, /*RequiresADL*/false); + } + /// Build a new conditional operator expression. /// /// By default, performs semantic analysis to build the new expression. @@ -2417,7 +2428,7 @@ public: ExprResult RebuildInitList(SourceLocation LBraceLoc, MultiExprArg Inits, SourceLocation RBraceLoc) { - return SemaRef.ActOnInitList(LBraceLoc, Inits, RBraceLoc); + return SemaRef.BuildInitList(LBraceLoc, Inits, RBraceLoc); } /// Build a new designated initializer expression. @@ -3019,6 +3030,25 @@ 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, + NamedDecl *FoundDecl, ConceptDecl *NamedConcept, + TemplateArgumentListInfo *TALI) { + CXXScopeSpec SS; + SS.Adopt(NNS); + ExprResult Result = getSema().CheckConceptTemplateId(SS, TemplateKWLoc, + ConceptNameLoc, + FoundDecl, + NamedConcept, TALI); + if (Result.isInvalid()) + return ExprError(); + return Result; + } + + /// \brief Build a new Objective-C boxed expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. ExprResult RebuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { return getSema().BuildObjCBoxedExpr(SR, ValueExpr); } @@ -3309,16 +3339,14 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildAtomicExpr(SourceLocation BuiltinLoc, - MultiExprArg SubExprs, - QualType RetTy, + ExprResult RebuildAtomicExpr(SourceLocation BuiltinLoc, MultiExprArg SubExprs, AtomicExpr::AtomicOp Op, SourceLocation RParenLoc) { - // Just create the expression; there is not any interesting semantic - // analysis here because we can't actually build an AtomicExpr until - // we are sure it is semantically sound. - return new (SemaRef.Context) AtomicExpr(BuiltinLoc, SubExprs, RetTy, Op, - RParenLoc); + // Use this for all of the locations, since we don't know the difference + // between the call and the expr at this point. + SourceRange Range{BuiltinLoc, RParenLoc}; + return getSema().BuildAtomicExpr(Range, Range, RParenLoc, SubExprs, Op, + Sema::AtomicArgumentOrder::AST); } private: @@ -4641,7 +4669,7 @@ TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB, // Objective-C ARC can add lifetime qualifiers to the type that we're // referring to. TLB.TypeWasModifiedSafely( - Result->getAs<ReferenceType>()->getPointeeTypeAsWritten()); + Result->castAs<ReferenceType>()->getPointeeTypeAsWritten()); // r-value references can be rebuilt as l-value references. ReferenceTypeLoc NewTL; @@ -4729,12 +4757,25 @@ TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB, if (ElementType.isNull()) return QualType(); + // Prefer the expression from the TypeLoc; the other may have been uniqued. + Expr *OldSize = TL.getSizeExpr(); + if (!OldSize) + OldSize = const_cast<Expr*>(T->getSizeExpr()); + Expr *NewSize = nullptr; + if (OldSize) { + EnterExpressionEvaluationContext Unevaluated( + SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); + NewSize = getDerived().TransformExpr(OldSize).template getAs<Expr>(); + NewSize = SemaRef.ActOnConstantExpression(NewSize).get(); + } + QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || - ElementType != T->getElementType()) { + ElementType != T->getElementType() || + (T->getSizeExpr() && NewSize != OldSize)) { Result = getDerived().RebuildConstantArrayType(ElementType, T->getSizeModifier(), - T->getSize(), + T->getSize(), NewSize, T->getIndexTypeCVRQualifiers(), TL.getBracketsRange()); if (Result.isNull()) @@ -4748,15 +4789,7 @@ TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB, ArrayTypeLoc NewTL = TLB.push<ArrayTypeLoc>(Result); NewTL.setLBracketLoc(TL.getLBracketLoc()); NewTL.setRBracketLoc(TL.getRBracketLoc()); - - Expr *Size = TL.getSizeExpr(); - if (Size) { - EnterExpressionEvaluationContext Unevaluated( - SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); - Size = getDerived().TransformExpr(Size).template getAs<Expr>(); - Size = SemaRef.ActOnConstantExpression(Size).get(); - } - NewTL.setSizeExpr(Size); + NewTL.setSizeExpr(NewSize); return Result; } @@ -5928,7 +5961,7 @@ QualType TreeTransform<Derived>::TransformPipeType(TypeLocBuilder &TLB, QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ValueType != TL.getValueLoc().getType()) { - const PipeType *PT = Result->getAs<PipeType>(); + const PipeType *PT = Result->castAs<PipeType>(); bool isReadPipe = PT->isReadOnly(); Result = getDerived().RebuildPipeType(ValueType, TL.getKWLoc(), isReadPipe); if (Result.isNull()) @@ -8244,6 +8277,39 @@ StmtResult TreeTransform<Derived>::TransformOMPTaskLoopSimdDirective( } template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPMasterTaskLoopDirective( + OMPMasterTaskLoopDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_master_taskloop, DirName, + nullptr, D->getBeginLoc()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPMasterTaskLoopSimdDirective( + OMPMasterTaskLoopSimdDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_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>::TransformOMPParallelMasterTaskLoopDirective( + OMPParallelMasterTaskLoopDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock( + OMPD_parallel_master_taskloop, 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; @@ -9204,6 +9270,14 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) { if (!ND) return ExprError(); + NamedDecl *Found = ND; + if (E->getFoundDecl() != E->getDecl()) { + Found = cast_or_null<NamedDecl>( + getDerived().TransformDecl(E->getLocation(), E->getFoundDecl())); + if (!Found) + return ExprError(); + } + DeclarationNameInfo NameInfo = E->getNameInfo(); if (NameInfo.getName()) { NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo); @@ -9214,6 +9288,7 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) { if (!getDerived().AlwaysRebuild() && QualifierLoc == E->getQualifierLoc() && ND == E->getDecl() && + Found == E->getFoundDecl() && NameInfo.getName() == E->getDecl()->getDeclName() && !E->hasExplicitTemplateArgs()) { @@ -9236,7 +9311,7 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) { } return getDerived().RebuildDeclRefExpr(QualifierLoc, ND, NameInfo, - TemplateArgs); + Found, TemplateArgs); } template<typename Derived> @@ -9705,6 +9780,50 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) { LHS.get(), RHS.get()); } +template <typename Derived> +ExprResult TreeTransform<Derived>::TransformCXXRewrittenBinaryOperator( + CXXRewrittenBinaryOperator *E) { + CXXRewrittenBinaryOperator::DecomposedForm Decomp = E->getDecomposedForm(); + + ExprResult LHS = getDerived().TransformExpr(const_cast<Expr*>(Decomp.LHS)); + if (LHS.isInvalid()) + return ExprError(); + + ExprResult RHS = getDerived().TransformExpr(const_cast<Expr*>(Decomp.RHS)); + if (RHS.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && + LHS.get() == Decomp.LHS && + RHS.get() == Decomp.RHS) + return E; + + // Extract the already-resolved callee declarations so that we can restrict + // ourselves to using them as the unqualified lookup results when rebuilding. + UnresolvedSet<2> UnqualLookups; + Expr *PossibleBinOps[] = {E->getSemanticForm(), + const_cast<Expr *>(Decomp.InnerBinOp)}; + for (Expr *PossibleBinOp : PossibleBinOps) { + auto *Op = dyn_cast<CXXOperatorCallExpr>(PossibleBinOp->IgnoreImplicit()); + if (!Op) + continue; + auto *Callee = dyn_cast<DeclRefExpr>(Op->getCallee()->IgnoreImplicit()); + if (!Callee || isa<CXXMethodDecl>(Callee->getDecl())) + continue; + + // Transform the callee in case we built a call to a local extern + // declaration. + NamedDecl *Found = cast_or_null<NamedDecl>(getDerived().TransformDecl( + E->getOperatorLoc(), Callee->getFoundDecl())); + if (!Found) + return ExprError(); + UnqualLookups.addDecl(Found); + } + + return getDerived().RebuildCXXRewrittenBinaryOperator( + E->getOperatorLoc(), Decomp.Opcode, UnqualLookups, LHS.get(), RHS.get()); +} + template<typename Derived> ExprResult TreeTransform<Derived>::TransformCompoundAssignOperator( @@ -10982,6 +11101,23 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) { template<typename Derived> ExprResult +TreeTransform<Derived>::TransformConceptSpecializationExpr( + ConceptSpecializationExpr *E) { + const ASTTemplateArgumentListInfo *Old = E->getTemplateArgsAsWritten(); + TemplateArgumentListInfo TransArgs(Old->LAngleLoc, Old->RAngleLoc); + if (getDerived().TransformTemplateArguments(Old->getTemplateArgs(), + Old->NumTemplateArgs, TransArgs)) + return ExprError(); + + return getDerived().RebuildConceptSpecializationExpr( + E->getNestedNameSpecifierLoc(), E->getTemplateKWLoc(), + E->getConceptNameLoc(), E->getFoundDecl(), E->getNamedConcept(), + &TransArgs); +} + + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { TypeSourceInfo *T = getDerived().TransformType(E->getQueriedTypeSourceInfo()); if (!T) @@ -11318,10 +11454,14 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { } } + LambdaScopeInfo *LSI = getSema().PushLambdaScope(); + Sema::FunctionScopeRAII FuncScopeCleanup(getSema()); + // Transform the template parameters, and add them to the current // instantiation scope. The null case is handled correctly. auto TPL = getDerived().TransformTemplateParameterList( E->getTemplateParameterList()); + LSI->GLTemplateParameterList = TPL; // Transform the type of the original lambda's call operator. // The transformation MUST be done in the CurrentInstantiationScope since @@ -11348,10 +11488,6 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { NewCallOpType); } - LambdaScopeInfo *LSI = getSema().PushLambdaScope(); - Sema::FunctionScopeRAII FuncScopeCleanup(getSema()); - LSI->GLTemplateParameterList = TPL; - // Create the local class that will describe the lambda. CXXRecordDecl *OldClass = E->getLambdaClass(); CXXRecordDecl *Class @@ -11361,17 +11497,18 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { E->getCaptureDefault()); getDerived().transformedLocalDecl(OldClass, {Class}); - Optional<std::pair<unsigned, Decl*>> Mangling; + Optional<std::tuple<unsigned, bool, Decl *>> Mangling; if (getDerived().ReplacingOriginal()) - Mangling = std::make_pair(OldClass->getLambdaManglingNumber(), - OldClass->getLambdaContextDecl()); + Mangling = std::make_tuple(OldClass->getLambdaManglingNumber(), + OldClass->hasKnownLambdaInternalLinkage(), + OldClass->getLambdaContextDecl()); // Build the call operator. CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition( Class, E->getIntroducerRange(), NewCallOpTSI, E->getCallOperator()->getEndLoc(), NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(), - E->getCallOperator()->getConstexprKind(), Mangling); + E->getCallOperator()->getConstexprKind()); LSI->CallOperator = NewCallOperator; @@ -11391,6 +11528,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator}); + // Number the lambda for linkage purposes if necessary. + getSema().handleLambdaNumbering(Class, NewCallOperator, Mangling); + // Introduce the context of the call operator. Sema::ContextRAII SavedContext(getSema(), NewCallOperator, /*NewThisContext*/false); @@ -11663,7 +11803,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( } else { OldBase = nullptr; BaseType = getDerived().TransformType(E->getBaseType()); - ObjectType = BaseType->getAs<PointerType>()->getPointeeType(); + ObjectType = BaseType->castAs<PointerType>()->getPointeeType(); } // Transform the first part of the nested-name-specifier that qualifies @@ -12666,7 +12806,6 @@ TreeTransform<Derived>::TransformAsTypeExpr(AsTypeExpr *E) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformAtomicExpr(AtomicExpr *E) { - QualType RetTy = getDerived().TransformType(E->getType()); bool ArgumentChanged = false; SmallVector<Expr*, 8> SubExprs; SubExprs.reserve(E->getNumSubExprs()); @@ -12679,7 +12818,7 @@ TreeTransform<Derived>::TransformAtomicExpr(AtomicExpr *E) { return E; return getDerived().RebuildAtomicExpr(E->getBuiltinLoc(), SubExprs, - RetTy, E->getOp(), E->getRParenLoc()); + E->getOp(), E->getRParenLoc()); } //===----------------------------------------------------------------------===// @@ -12797,9 +12936,10 @@ QualType TreeTransform<Derived>::RebuildConstantArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, const llvm::APInt &Size, + Expr *SizeExpr, unsigned IndexTypeQuals, SourceRange BracketsRange) { - return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, nullptr, + return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, SizeExpr, IndexTypeQuals, BracketsRange); } @@ -13183,7 +13323,7 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base, if (Base->isTypeDependent() || Destroyed.getIdentifier() || (!isArrow && !BaseType->getAs<RecordType>()) || (isArrow && BaseType->getAs<PointerType>() && - !BaseType->getAs<PointerType>()->getPointeeType() + !BaseType->castAs<PointerType>()->getPointeeType() ->template getAs<RecordType>())){ // This pseudo-destructor expression is still a pseudo-destructor. return SemaRef.BuildPseudoDestructorExpr( diff --git a/lib/Sema/TypeLocBuilder.cpp b/lib/Sema/TypeLocBuilder.cpp index b451403544ed..2dcbbd83c691 100644 --- a/lib/Sema/TypeLocBuilder.cpp +++ b/lib/Sema/TypeLocBuilder.cpp @@ -51,7 +51,7 @@ void TypeLocBuilder::grow(size_t NewCapacity) { &Buffer[Index], Capacity - Index); - if (Buffer != InlineBuffer.buffer) + if (Buffer != InlineBuffer) delete[] Buffer; Buffer = NewBuffer; diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h index 1e6883926a80..738f731c9fe2 100644 --- a/lib/Sema/TypeLocBuilder.h +++ b/lib/Sema/TypeLocBuilder.h @@ -39,18 +39,16 @@ class TypeLocBuilder { /// The inline buffer. enum { BufferMaxAlignment = alignof(void *) }; - llvm::AlignedCharArray<BufferMaxAlignment, InlineCapacity> InlineBuffer; + alignas(BufferMaxAlignment) char InlineBuffer[InlineCapacity]; unsigned NumBytesAtAlign4, NumBytesAtAlign8; - public: +public: TypeLocBuilder() - : Buffer(InlineBuffer.buffer), Capacity(InlineCapacity), - Index(InlineCapacity), NumBytesAtAlign4(0), NumBytesAtAlign8(0) - { - } + : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity), + NumBytesAtAlign4(0), NumBytesAtAlign8(0) {} ~TypeLocBuilder() { - if (Buffer != InlineBuffer.buffer) + if (Buffer != InlineBuffer) delete[] Buffer; } |