diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-10-23 17:52:09 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-10-23 17:52:09 +0000 |
commit | 519fc96c475680de2cc49e7811dbbfadb912cbcc (patch) | |
tree | 310ca684459b7e9ae13c9a3b9abf308b3a634afe /lib/Sema | |
parent | 2298981669bf3bd63335a4be179bc0f96823a8f4 (diff) | |
download | src-vendor/clang.tar.gz src-vendor/clang.zip |
Vendor import of stripped clang trunk r375505, the last commit beforevendor/clang/clang-trunk-r375505vendor/clang
the upstream Subversion repository was made read-only, and the LLVM
project migrated to GitHub:
https://llvm.org/svn/llvm-project/cfe/trunk@375505
Notes
Notes:
svn path=/vendor/clang/dist/; revision=353942
svn path=/vendor/clang/clang-r375505/; revision=353943; tag=vendor/clang/clang-trunk-r375505
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 IsVariableUsedInMapCl |