summaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp82
-rw-r--r--lib/Sema/DeclSpec.cpp15
-rw-r--r--lib/Sema/OpenCLBuiltins.td744
-rw-r--r--lib/Sema/ParsedAttr.cpp65
-rw-r--r--lib/Sema/Sema.cpp91
-rw-r--r--lib/Sema/SemaAccess.cpp6
-rw-r--r--lib/Sema/SemaAttr.cpp135
-rw-r--r--lib/Sema/SemaCUDA.cpp93
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp2
-rw-r--r--lib/Sema/SemaCast.cpp17
-rw-r--r--lib/Sema/SemaChecking.cpp612
-rw-r--r--lib/Sema/SemaCodeComplete.cpp3
-rw-r--r--lib/Sema/SemaConcept.cpp125
-rw-r--r--lib/Sema/SemaCoroutine.cpp2
-rw-r--r--lib/Sema/SemaDecl.cpp884
-rw-r--r--lib/Sema/SemaDeclAttr.cpp1101
-rw-r--r--lib/Sema/SemaDeclCXX.cpp577
-rw-r--r--lib/Sema/SemaDeclObjC.cpp14
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp23
-rw-r--r--lib/Sema/SemaExpr.cpp991
-rw-r--r--lib/Sema/SemaExprCXX.cpp295
-rw-r--r--lib/Sema/SemaExprMember.cpp20
-rw-r--r--lib/Sema/SemaExprObjC.cpp4
-rw-r--r--lib/Sema/SemaInit.cpp1210
-rw-r--r--lib/Sema/SemaLambda.cpp127
-rw-r--r--lib/Sema/SemaLookup.cpp853
-rw-r--r--lib/Sema/SemaModule.cpp2
-rw-r--r--lib/Sema/SemaObjCProperty.cpp14
-rw-r--r--lib/Sema/SemaOpenMP.cpp1880
-rw-r--r--lib/Sema/SemaOverload.cpp653
-rw-r--r--lib/Sema/SemaStmt.cpp151
-rw-r--r--lib/Sema/SemaStmtAsm.cpp32
-rw-r--r--lib/Sema/SemaStmtAttr.cpp31
-rw-r--r--lib/Sema/SemaTemplate.cpp274
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp47
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp69
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp213
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp74
-rw-r--r--lib/Sema/SemaType.cpp214
-rw-r--r--lib/Sema/TreeTransform.h220
-rw-r--r--lib/Sema/TypeLocBuilder.cpp2
-rw-r--r--lib/Sema/TypeLocBuilder.h12
42 files changed, 8257 insertions, 3722 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index ce01909f1858..2c70c0599ecf 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -159,6 +159,20 @@ public:
S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_always)
<< DiagRange << isAlwaysTrue;
}
+
+ void compareBitwiseOr(const BinaryOperator *B) override {
+ if (HasMacroID(B))
+ return;
+
+ SourceRange DiagRange = B->getSourceRange();
+ S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange;
+ }
+
+ static bool hasActiveDiagnostics(DiagnosticsEngine &Diags,
+ SourceLocation Loc) {
+ return !Diags.isIgnored(diag::warn_tautological_overlap_comparison, Loc) ||
+ !Diags.isIgnored(diag::warn_comparison_bitwise_or, Loc);
+ }
};
} // anonymous namespace
@@ -1215,7 +1229,7 @@ static StringRef getFallthroughAttrSpelling(Preprocessor &PP,
tok::r_square, tok::r_square
};
- bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17;
+ bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17 && !PP.getLangOpts().C2x;
StringRef MacroName;
if (PreferClangAttr)
@@ -1224,24 +1238,19 @@ static StringRef getFallthroughAttrSpelling(Preprocessor &PP,
MacroName = PP.getLastMacroWithSpelling(Loc, FallthroughTokens);
if (MacroName.empty() && !PreferClangAttr)
MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens);
- if (MacroName.empty())
- MacroName = PreferClangAttr ? "[[clang::fallthrough]]" : "[[fallthrough]]";
+ if (MacroName.empty()) {
+ if (!PreferClangAttr)
+ MacroName = "[[fallthrough]]";
+ else if (PP.getLangOpts().CPlusPlus)
+ MacroName = "[[clang::fallthrough]]";
+ else
+ MacroName = "__attribute__((fallthrough))";
+ }
return MacroName;
}
static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
bool PerFunction) {
- // Only perform this analysis when using [[]] attributes. There is no good
- // workflow for this warning when not using C++11. There is no good way to
- // silence the warning (no attribute is available) unless we are using
- // [[]] attributes. One could use pragmas to silence the warning, but as a
- // general solution that is gross and not in the spirit of this warning.
- //
- // NOTE: This an intermediate solution. There are on-going discussions on
- // how to properly support this warning outside of C++11 with an annotation.
- if (!AC.getASTContext().getLangOpts().DoubleSquareBracketAttributes)
- return;
-
FallthroughMapper FM(S);
FM.TraverseStmt(AC.getBody());
@@ -1281,25 +1290,24 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
SourceLocation L = Label->getBeginLoc();
if (L.isMacroID())
continue;
- if (S.getLangOpts().CPlusPlus11) {
- const Stmt *Term = B->getTerminatorStmt();
- // Skip empty cases.
- while (B->empty() && !Term && B->succ_size() == 1) {
- B = *B->succ_begin();
- Term = B->getTerminatorStmt();
- }
- if (!(B->empty() && Term && isa<BreakStmt>(Term))) {
- Preprocessor &PP = S.getPreprocessor();
- StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L);
- SmallString<64> TextToInsert(AnnotationSpelling);
- TextToInsert += "; ";
- S.Diag(L, diag::note_insert_fallthrough_fixit) <<
- AnnotationSpelling <<
- FixItHint::CreateInsertion(L, TextToInsert);
- }
+
+ const Stmt *Term = B->getTerminatorStmt();
+ // Skip empty cases.
+ while (B->empty() && !Term && B->succ_size() == 1) {
+ B = *B->succ_begin();
+ Term = B->getTerminatorStmt();
+ }
+ if (!(B->empty() && Term && isa<BreakStmt>(Term))) {
+ Preprocessor &PP = S.getPreprocessor();
+ StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L);
+ SmallString<64> TextToInsert(AnnotationSpelling);
+ TextToInsert += "; ";
+ S.Diag(L, diag::note_insert_fallthrough_fixit)
+ << AnnotationSpelling
+ << FixItHint::CreateInsertion(L, TextToInsert);
}
- S.Diag(L, diag::note_insert_break_fixit) <<
- FixItHint::CreateInsertion(L, "break; ");
+ S.Diag(L, diag::note_insert_break_fixit)
+ << FixItHint::CreateInsertion(L, "break; ");
}
}
@@ -2076,10 +2084,9 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
.setAlwaysAdd(Stmt::AttributedStmtClass);
}
- // Install the logical handler for -Wtautological-overlap-compare
+ // Install the logical handler.
llvm::Optional<LogicalErrorHandler> LEH;
- if (!Diags.isIgnored(diag::warn_tautological_overlap_comparison,
- D->getBeginLoc())) {
+ if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {
LEH.emplace(S);
AC.getCFGBuildOptions().Observer = &*LEH;
}
@@ -2228,9 +2235,8 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
checkThrowInNonThrowingFunc(S, FD, AC);
// If none of the previous checks caused a CFG build, trigger one here
- // for -Wtautological-overlap-compare
- if (!Diags.isIgnored(diag::warn_tautological_overlap_comparison,
- D->getBeginLoc())) {
+ // for the logical error handler.
+ if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {
AC.getCFG();
}
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index 77e5eb095693..639231c87232 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -569,6 +569,7 @@ const char *DeclSpec::getSpecifierName(ConstexprSpecKind C) {
case CSK_unspecified: return "unspecified";
case CSK_constexpr: return "constexpr";
case CSK_consteval: return "consteval";
+ case CSK_constinit: return "constinit";
}
llvm_unreachable("Unknown ConstexprSpecKind");
}
@@ -1036,13 +1037,9 @@ bool DeclSpec::setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec,
bool DeclSpec::SetConstexprSpec(ConstexprSpecKind ConstexprKind,
SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID) {
- if (getConstexprSpecifier() != CSK_unspecified) {
- if (getConstexprSpecifier() == CSK_consteval || ConstexprKind == CSK_consteval)
- return BadSpecifier(ConstexprKind, getConstexprSpecifier(), PrevSpec, DiagID);
- DiagID = diag::warn_duplicate_declspec;
- PrevSpec = "constexpr";
- return true;
- }
+ if (getConstexprSpecifier() != CSK_unspecified)
+ return BadSpecifier(ConstexprKind, getConstexprSpecifier(), PrevSpec,
+ DiagID);
ConstexprSpecifier = ConstexprKind;
ConstexprLoc = Loc;
return false;
@@ -1291,8 +1288,10 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
<< (TypeSpecType == TST_char16 ? "char16_t" : "char32_t");
if (getConstexprSpecifier() == CSK_constexpr)
S.Diag(ConstexprLoc, diag::warn_cxx98_compat_constexpr);
- if (getConstexprSpecifier() == CSK_consteval)
+ else if (getConstexprSpecifier() == CSK_consteval)
S.Diag(ConstexprLoc, diag::warn_cxx20_compat_consteval);
+ else if (getConstexprSpecifier() == CSK_constinit)
+ S.Diag(ConstexprLoc, diag::warn_cxx20_compat_constinit);
// C++ [class.friend]p6:
// No storage-class-specifier shall appear in the decl-specifier-seq
// of a friend declaration.
diff --git a/lib/Sema/OpenCLBuiltins.td b/lib/Sema/OpenCLBuiltins.td
index 7e37e55dbafa..298614059467 100644
--- a/lib/Sema/OpenCLBuiltins.td
+++ b/lib/Sema/OpenCLBuiltins.td
@@ -20,75 +20,164 @@
//===----------------------------------------------------------------------===//
// Versions of OpenCL
class Version<int _Version> {
- int Version = _Version;
+ int ID = _Version;
}
-def CL10: Version<100>;
-def CL11: Version<110>;
-def CL12: Version<120>;
-def CL20: Version<200>;
+def CLAll : Version< 0>;
+def CL10 : Version<100>;
+def CL11 : Version<110>;
+def CL12 : Version<120>;
+def CL20 : Version<200>;
// Address spaces
// Pointer types need to be assigned an address space.
class AddressSpace<string _AS> {
- string AddrSpace = _AS;
+ string Name = _AS;
}
-def default_as : AddressSpace<"clang::LangAS::Default">;
-def private_as : AddressSpace<"clang::LangAS::opencl_private">;
-def global_as : AddressSpace<"clang::LangAS::opencl_global">;
-def constant_as : AddressSpace<"clang::LangAS::opencl_constant">;
-def local_as : AddressSpace<"clang::LangAS::opencl_local">;
-def generic_as : AddressSpace<"clang::LangAS::opencl_generic">;
+def DefaultAS : AddressSpace<"clang::LangAS::Default">;
+def PrivateAS : AddressSpace<"clang::LangAS::opencl_private">;
+def GlobalAS : AddressSpace<"clang::LangAS::opencl_global">;
+def ConstantAS : AddressSpace<"clang::LangAS::opencl_constant">;
+def LocalAS : AddressSpace<"clang::LangAS::opencl_local">;
+def GenericAS : AddressSpace<"clang::LangAS::opencl_generic">;
-// Qualified Type. Allow to retrieve one ASTContext QualType.
-class QualType<string _Name> {
+// Qualified Type. These map to ASTContext::QualType.
+class QualType<string _Name, bit _IsAbstract=0> {
// Name of the field or function in a clang::ASTContext
// E.g. Name="IntTy" for the int type, and "getIntPtrType()" for an intptr_t
string Name = _Name;
+ // Some QualTypes in this file represent an abstract type for which there is
+ // no corresponding AST QualType, e.g. a GenType or an `image2d_t` type
+ // without access qualifiers.
+ bit IsAbstract = _IsAbstract;
}
-// Helper class to store type access qualifiers (volatile, const, ...).
-class Qualifier<string _QualName> {
- string QualName = _QualName;
+// List of integers.
+class IntList<string _Name, list<int> _List> {
+ string Name = _Name;
+ list<int> List = _List;
}
//===----------------------------------------------------------------------===//
// OpenCL C classes for types
//===----------------------------------------------------------------------===//
-// OpenCL types (int, float, ...)
+// OpenCL C basic data types (int, float, image2d_t, ...).
+// Its child classes can represent concrete types (e.g. VectorType) or
+// abstract types (e.g. GenType).
class Type<string _Name, QualType _QTName> {
- // Name of the Type
+ // Name of the Type.
string Name = _Name;
- // QualType associated with this type
+ // QualType associated with this type.
QualType QTName = _QTName;
- // Size of the vector (if applicable)
- int VecWidth = 0;
- // Is pointer
+ // Size of the vector (if applicable).
+ int VecWidth = 1;
+ // Is a pointer.
bit IsPointer = 0;
- // List of qualifiers associated with the type (volatile, ...)
- list<Qualifier> QualList = [];
- // Address space
- string AddrSpace = "clang::LangAS::Default";
+ // "const" qualifier.
+ bit IsConst = 0;
+ // "volatile" qualifier.
+ bit IsVolatile = 0;
// Access qualifier. Must be one of ("RO", "WO", "RW").
string AccessQualifier = "";
+ // Address space.
+ string AddrSpace = DefaultAS.Name;
}
-// OpenCL vector types (e.g. int2, int3, int16, float8, ...)
+// OpenCL vector types (e.g. int2, int3, int16, float8, ...).
class VectorType<Type _Ty, int _VecWidth> : Type<_Ty.Name, _Ty.QTName> {
- int VecWidth = _VecWidth;
+ let VecWidth = _VecWidth;
+ let AccessQualifier = "";
+ // Inherited fields
+ let IsPointer = _Ty.IsPointer;
+ let IsConst = _Ty.IsConst;
+ let IsVolatile = _Ty.IsVolatile;
+ let AddrSpace = _Ty.AddrSpace;
}
-// OpenCL pointer types (e.g. int*, float*, ...)
-class PointerType<Type _Ty, AddressSpace _AS = global_as> :
+// OpenCL pointer types (e.g. int*, float*, ...).
+class PointerType<Type _Ty, AddressSpace _AS = DefaultAS> :
Type<_Ty.Name, _Ty.QTName> {
- bit IsPointer = 1;
- string AddrSpace = _AS.AddrSpace;
+ let AddrSpace = _AS.Name;
+ // Inherited fields
+ let VecWidth = _Ty.VecWidth;
+ let IsPointer = 1;
+ let IsConst = _Ty.IsConst;
+ let IsVolatile = _Ty.IsVolatile;
+ let AccessQualifier = _Ty.AccessQualifier;
+}
+
+// OpenCL const types (e.g. const int).
+class ConstType<Type _Ty> : Type<_Ty.Name, _Ty.QTName> {
+ let IsConst = 1;
+ // Inherited fields
+ let VecWidth = _Ty.VecWidth;
+ let IsPointer = _Ty.IsPointer;
+ let IsVolatile = _Ty.IsVolatile;
+ let AccessQualifier = _Ty.AccessQualifier;
+ let AddrSpace = _Ty.AddrSpace;
+}
+
+// OpenCL volatile types (e.g. volatile int).
+class VolatileType<Type _Ty> : Type<_Ty.Name, _Ty.QTName> {
+ let IsVolatile = 1;
+ // Inherited fields
+ let VecWidth = _Ty.VecWidth;
+ let IsPointer = _Ty.IsPointer;
+ let IsConst = _Ty.IsConst;
+ let AccessQualifier = _Ty.AccessQualifier;
+ let AddrSpace = _Ty.AddrSpace;
}
-// OpenCL image types (e.g. image2d_t, ...)
-class ImageType<Type _Ty, QualType _QTName, string _AccessQualifier> :
- Type<_Ty.Name, _QTName> {
+// OpenCL image types (e.g. image2d).
+class ImageType<Type _Ty, string _AccessQualifier> :
+ Type<_Ty.Name, QualType<_Ty.QTName.Name#_AccessQualifier#"Ty", 0>> {
+ let VecWidth = 0;
let AccessQualifier = _AccessQualifier;
+ // Inherited fields
+ let IsPointer = _Ty.IsPointer;
+ let IsConst = _Ty.IsConst;
+ let IsVolatile = _Ty.IsVolatile;
+ let AddrSpace = _Ty.AddrSpace;
+}
+
+// List of Types.
+class TypeList<string _Name, list<Type> _Type> {
+ string Name = _Name;
+ list<Type> List = _Type;
+}
+
+// A GenericType is an abstract type that defines a set of types as a
+// combination of Types and vector sizes.
+//
+// For example, if TypeList = <int, float> and VectorList = <1, 2, 4>, then it
+// represents <int, int2, int4, float, float2, float4>.
+//
+// Some rules apply when using multiple GenericType arguments in a declaration:
+// 1. The number of vector sizes must be equal or 1 for all gentypes in a
+// declaration.
+// 2. The number of Types must be equal or 1 for all gentypes in a
+// declaration.
+// 3. Generic types are combined by iterating over all generic types at once.
+// For example, for the following GenericTypes
+// GenT1 = GenericType<half, [1, 2]> and
+// GenT2 = GenericType<float, int, [1, 2]>
+// A declaration f(GenT1, GenT2) results in the combinations
+// f(half, float), f(half2, float2), f(half, int), f(half2, int2) .
+// 4. "sgentype" from the OpenCL specification is supported by specifying
+// a single vector size.
+// For example, for the following GenericTypes
+// GenT = GenericType<half, int, [1, 2]> and
+// SGenT = GenericType<half, int, [1]>
+// A declaration f(GenT, SGenT) results in the combinations
+// f(half, half), f(half2, half), f(int, int), f(int2, int) .
+class GenericType<string _Ty, TypeList _TypeList, IntList _VectorList> :
+ Type<_Ty, QualType<"null", 1>> {
+ // Possible element types of the generic type.
+ TypeList TypeList = _TypeList;
+ // Possible vector sizes of the types in the TypeList.
+ IntList VectorList = _VectorList;
+ // The VecWidth field is ignored for GenericTypes. Use VectorList instead.
+ let VecWidth = 0;
}
//===----------------------------------------------------------------------===//
@@ -103,141 +192,124 @@ class Builtin<string _Name, list<Type> _Signature> {
list<Type> Signature = _Signature;
// OpenCL Extension to which the function belongs (cl_khr_subgroups, ...)
string Extension = "";
- // OpenCL Version to which the function belongs (CL10, ...)
- Version Version = CL10;
+ // Version of OpenCL from which the function is available (e.g.: CL10).
+ // MinVersion is inclusive.
+ Version MinVersion = CL10;
+ // Version of OpenCL from which the function is not supported anymore.
+ // MaxVersion is exclusive.
+ // CLAll makes the function available for all versions.
+ Version MaxVersion = CLAll;
}
//===----------------------------------------------------------------------===//
-// Multiclass definitions
+// Definitions of OpenCL C types
//===----------------------------------------------------------------------===//
-// multiclass BifN: Creates Builtin class instances for OpenCL builtin
-// functions with N arguments.
-// _Name : Name of the function
-// _Signature : Signature of the function (list of the Type used by the
-// function, the first one being the return type).
-// _IsVector : List of bit indicating if the type in the _Signature at the
-// same index is to be a vector in the multiple overloads. The
-// list must have at least one non-zero value.
-multiclass Bif0<string _Name, list<Type> _Signature, list<bit> _IsVector> {
- def : Builtin<_Name, _Signature>;
- foreach v = [2, 3, 4, 8, 16] in {
- def : Builtin<_Name,
- [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0])]>;
- }
-}
-multiclass Bif1<string _Name, list<Type> _Signature, list<bit> _IsVector> {
- def : Builtin<_Name, _Signature>;
- foreach v = [2, 3, 4, 8, 16] in {
- def : Builtin<_Name,
- [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0]),
- !if(_IsVector[1], VectorType<_Signature[1], v>, _Signature[1])]>;
- }
-}
-multiclass Bif2<string _Name, list<Type> _Signature, list<bit> _IsVector> {
- def : Builtin<_Name, _Signature>;
- foreach v = [2, 3, 4, 8, 16] in {
- def : Builtin<_Name,
- [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0]),
- !if(_IsVector[1], VectorType<_Signature[1], v>, _Signature[1]),
- !if(_IsVector[2], VectorType<_Signature[2], v>, _Signature[2])]>;
- }
-}
-multiclass Bif3<string _Name, list<Type> _Signature, list<bit> _IsVector> {
- def : Builtin<_Name, _Signature>;
- foreach v = [2, 3, 4, 8, 16] in {
- def : Builtin<_Name,
- [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0]),
- !if(_IsVector[1], VectorType<_Signature[1], v>, _Signature[1]),
- !if(_IsVector[2], VectorType<_Signature[2], v>, _Signature[2]),
- !if(_IsVector[3], VectorType<_Signature[3], v>, _Signature[3])]>;
- }
-}
+
+// OpenCL v1.0/1.2/2.0 s6.1.1: Built-in Scalar Data Types.
+def Bool : Type<"bool", QualType<"BoolTy">>;
+def Char : Type<"char", QualType<"CharTy">>;
+def UChar : Type<"uchar", QualType<"UnsignedCharTy">>;
+def Short : Type<"short", QualType<"ShortTy">>;
+def UShort : Type<"ushort", QualType<"UnsignedShortTy">>;
+def Int : Type<"int", QualType<"IntTy">>;
+def UInt : Type<"uint", QualType<"UnsignedIntTy">>;
+def Long : Type<"long", QualType<"LongTy">>;
+def ULong : Type<"ulong", QualType<"UnsignedLongTy">>;
+def Float : Type<"float", QualType<"FloatTy">>;
+def Double : Type<"double", QualType<"DoubleTy">>;
+def Half : Type<"half", QualType<"HalfTy">>;
+def Size : Type<"size_t", QualType<"getSizeType()">>;
+def PtrDiff : Type<"ptrdiff_t", QualType<"getPointerDiffType()">>;
+def IntPtr : Type<"intptr_t", QualType<"getIntPtrType()">>;
+def UIntPtr : Type<"uintPtr_t", QualType<"getUIntPtrType()">>;
+def Void : Type<"void_t", QualType<"VoidTy">>;
+
+// OpenCL v1.0/1.2/2.0 s6.1.2: Built-in Vector Data Types.
+// Built-in vector data types are created by TableGen's OpenCLBuiltinEmitter.
+
+// OpenCL v1.0/1.2/2.0 s6.1.3: Other Built-in Data Types.
+// The image definitions are "abstract". They should not be used without
+// specifying an access qualifier (RO/WO/RW).
+def Image1d : Type<"Image1d", QualType<"OCLImage1d", 1>>;
+def Image2d : Type<"Image2d", QualType<"OCLImage2d", 1>>;
+def Image3d : Type<"Image3d", QualType<"OCLImage3d", 1>>;
+def Image1dArray : Type<"Image1dArray", QualType<"OCLImage1dArray", 1>>;
+def Image1dBuffer : Type<"Image1dBuffer", QualType<"OCLImage1dBuffer", 1>>;
+def Image2dArray : Type<"Image2dArray", QualType<"OCLImage2dArray", 1>>;
+def Image2dDepth : Type<"Image2dDepth", QualType<"OCLImage2dDepth", 1>>;
+def Image2dArrayDepth : Type<"Image2dArrayDepth", QualType<"OCLImage2dArrayDepth", 1>>;
+def Image2dMsaa : Type<"Image2dMsaa", QualType<"OCLImage2dMSAA", 1>>;
+def Image2dArrayMsaa : Type<"Image2dArrayMsaa", QualType<"OCLImage2dArrayMSAA", 1>>;
+def Image2dMsaaDepth : Type<"Image2dMsaaDepth", QualType<"OCLImage2dMSAADepth", 1>>;
+def Image2dArrayMsaaDepth : Type<"Image2dArrayMsaaDepth", QualType<"OCLImage2dArrayMSAADepth", 1>>;
+
+def Sampler : Type<"Sampler", QualType<"OCLSamplerTy">>;
+def Event : Type<"Event", QualType<"OCLEventTy">>;
+
//===----------------------------------------------------------------------===//
-// Definitions of OpenCL C types
+// Definitions of OpenCL gentype variants
//===----------------------------------------------------------------------===//
-// OpenCL v1.2 s6.1.1: Built-in Scalar Data Types
-def bool_t : Type<"bool", QualType<"BoolTy">>;
-def char_t : Type<"char", QualType<"CharTy">>;
-def uchar_t : Type<"uchar", QualType<"UnsignedCharTy">>;
-def short_t : Type<"short", QualType<"ShortTy">>;
-def ushort_t : Type<"ushort", QualType<"UnsignedShortTy">>;
-def int_t : Type<"int", QualType<"IntTy">>;
-def uint_t : Type<"uint", QualType<"UnsignedIntTy">>;
-def long_t : Type<"long", QualType<"LongTy">>;
-def ulong_t : Type<"ulong", QualType<"UnsignedLongTy">>;
-def float_t : Type<"float", QualType<"FloatTy">>;
-def double_t : Type<"double", QualType<"DoubleTy">>;
-def half_t : Type<"half", QualType<"HalfTy">>;
-def size_t : Type<"size_t", QualType<"getSizeType()">>;
-def ptrdiff_t : Type<"ptrdiff_t", QualType<"getPointerDiffType()">>;
-def intptr_t : Type<"intptr_t", QualType<"getIntPtrType()">>;
-def uintptr_t : Type<"uintptr_t", QualType<"getUIntPtrType()">>;
-def void_t : Type<"void", QualType<"VoidTy">>;
-
-// OpenCL v1.2 s6.1.2: Built-in Vector Data Types
-foreach v = [2, 3, 4, 8, 16] in {
- def char#v#_t : VectorType<char_t, v>;
- def uchar#v#_t : VectorType<uchar_t, v>;
- def short#v#_t : VectorType<short_t, v>;
- def ushort#v#_t : VectorType<ushort_t, v>;
- def "int"#v#_t : VectorType<int_t, v>;
- def uint#v#_t : VectorType<uint_t, v>;
- def long#v#_t : VectorType<long_t, v>;
- def ulong#v#_t : VectorType<ulong_t, v>;
- def float#v#_t : VectorType<float_t, v>;
- def double#v#_t : VectorType<double_t, v>;
- def half#v#_t : VectorType<half_t, v>;
-}
-
-// OpenCL v1.2 s6.1.3: Other Built-in Data Types
-// These definitions with a "null" name are "abstract". They should not
-// be used in definitions of Builtin functions.
-def image2d_t : Type<"image2d_t", QualType<"null">>;
-def image3d_t : Type<"image3d_t", QualType<"null">>;
-def image2d_array_t : Type<"image2d_array_t", QualType<"null">>;
-def image1d_t : Type<"image1d_t", QualType<"null">>;
-def image1d_buffer_t : Type<"image1d_buffer_t", QualType<"null">>;
-def image1d_array_t : Type<"image1d_array_t", QualType<"null">>;
-// Unlike the few functions above, the following definitions can be used
-// in definitions of Builtin functions (they have a QualType with a name).
-foreach v = ["RO", "WO", "RW"] in {
- def image2d_#v#_t : ImageType<image2d_t,
- QualType<"OCLImage2d"#v#"Ty">,
- v>;
- def image3d_#v#_t : ImageType<image3d_t,
- QualType<"OCLImage3d"#v#"Ty">,
- v>;
- def image2d_array#v#_t : ImageType<image2d_array_t,
- QualType<"OCLImage2dArray"#v#"Ty">,
- v>;
- def image1d_#v#_t : ImageType<image1d_t,
- QualType<"OCLImage1d"#v#"Ty">,
- v>;
- def image1d_buffer#v#_t : ImageType<image1d_buffer_t,
- QualType<"OCLImage1dBuffer"#v#"Ty">,
- v>;
- def image1d_array#v#_t : ImageType<image1d_array_t,
- QualType<"OCLImage1dArray"#v#"Ty">,
- v>;
-}
-
-def sampler_t : Type<"sampler_t", QualType<"OCLSamplerTy">>;
-def event_t : Type<"event_t", QualType<"OCLEventTy">>;
+// The OpenCL specification often uses "gentype" in builtin function
+// declarations to indicate that a builtin function is available with various
+// argument and return types. The types represented by "gentype" vary between
+// different parts of the specification. The following definitions capture
+// the different type lists for gentypes in different parts of the
+// specification.
+
+// Vector width lists.
+def VecAndScalar: IntList<"VecAndScalar", [1, 2, 3, 4, 8, 16]>;
+def VecNoScalar : IntList<"VecNoScalar", [2, 3, 4, 8, 16]>;
+def Vec1 : IntList<"Vec1", [1]>;
+
+// Type lists.
+def TLAll : TypeList<"TLAll", [Char, UChar, Short, UShort, Int, UInt, Long, ULong, Float, Double, Half]>;
+def TLFloat : TypeList<"TLFloat", [Float, Double, Half]>;
+
+def TLAllInts : TypeList<"TLAllInts", [Char, UChar, Short, UShort, Int, UInt, Long, ULong]>;
+
+// GenType definitions for multiple base types (e.g. all floating point types,
+// or all integer types).
+// All types
+def AGenTypeN : GenericType<"AGenTypeN", TLAll, VecAndScalar>;
+def AGenTypeNNoScalar : GenericType<"AGenTypeNNoScalar", TLAll, VecNoScalar>;
+// All integer
+def AIGenType1 : GenericType<"AIGenType1", TLAllInts, Vec1>;
+def AIGenTypeN : GenericType<"AIGenTypeN", TLAllInts, VecAndScalar>;
+def AIGenTypeNNoScalar : GenericType<"AIGenTypeNNoScalar", TLAllInts, VecNoScalar>;
+// Float
+def FGenTypeN : GenericType<"FGenTypeN", TLFloat, VecAndScalar>;
+
+// GenType definitions for every single base type (e.g. fp32 only).
+// Names are like: GenTypeFloatVecAndScalar.
+foreach Type = [Char, UChar, Short, UShort,
+ Int, UInt, Long, ULong,
+ Float, Double, Half] in {
+ foreach VecSizes = [VecAndScalar, VecNoScalar] in {
+ def "GenType" # Type # VecSizes :
+ GenericType<"GenType" # Type # VecSizes,
+ TypeList<"GL" # Type.Name, [Type]>,
+ VecSizes>;
+ }
+}
+
//===----------------------------------------------------------------------===//
// Definitions of OpenCL builtin functions
//===----------------------------------------------------------------------===//
-// OpenCL v1.2 s6.2.3: Explicit Conversions
-// Generate the convert_ builtins.
-foreach RType = [float_t, double_t, char_t, uchar_t, short_t, ushort_t,
- int_t, uint_t, long_t, ulong_t] in {
- foreach IType = [float_t, double_t, char_t, uchar_t, short_t, ushort_t,
- int_t, uint_t, long_t, ulong_t] in {
+//--------------------------------------------------------------------
+// OpenCL v1.1/1.2/2.0 s6.2.3 - Explicit conversions.
+// OpenCL v2.0 Extensions s5.1.1 and s6.1.1 - Conversions.
+
+// Generate the convert_* builtins functions.
+foreach RType = [Float, Double, Half, Char, UChar, Short,
+ UShort, Int, UInt, Long, ULong] in {
+ foreach IType = [Float, Double, Half, Char, UChar, Short,
+ UShort, Int, UInt, Long, ULong] in {
foreach sat = ["", "_sat"] in {
- foreach rte = ["", "_rte", "_rtz", "_rtp", "_rtn"] in {
- def : Builtin<"convert_" # RType.Name # sat # rte, [RType, IType]>;
+ foreach rnd = ["", "_rte", "_rtn", "_rtp", "_rtz"] in {
+ def : Builtin<"convert_" # RType.Name # sat # rnd, [RType, IType]>;
foreach v = [2, 3, 4, 8, 16] in {
- def : Builtin<"convert_" # RType.Name # v # sat # rte,
+ def : Builtin<"convert_" # RType.Name # v # sat # rnd,
[VectorType<RType, v>,
VectorType<IType, v>]>;
}
@@ -246,51 +318,357 @@ foreach RType = [float_t, double_t, char_t, uchar_t, short_t, ushort_t,
}
}
-// OpenCL v1.2 s6.12.1: Work-Item Functions
-def get_work_dim : Builtin<"get_work_dim", [uint_t]>;
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.1, v1.2 s6.12.1, v2.0 s6.13.1 - Work-item Functions
+// --- Table 7 ---
+def : Builtin<"get_work_dim", [UInt]>;
foreach name = ["get_global_size", "get_global_id", "get_local_size",
"get_local_id", "get_num_groups", "get_group_id",
"get_global_offset"] in {
- def : Builtin<name, [size_t, uint_t]>;
+ def : Builtin<name, [Size, UInt]>;
+}
+
+let MinVersion = CL20 in {
+ def : Builtin<"get_enqueued_local_size", [Size, UInt]>;
+ foreach name = ["get_global_linear_id", "get_local_linear_id"] in {
+ def : Builtin<name, [Size]>;
+ }
+}
+
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.7, v1.2 s6.12.7, v2.0 s6.13.7 - Vector Data Load and Store Functions
+// OpenCL Extension v1.1 s9.3.6 and s9.6.6, v1.2 s9.5.6, v2.0 s9.4.6, v2.0 s5.1.6 and 6.1.6 - Vector Data Load and Store Functions
+// --- Table 15 ---
+// Variants for OpenCL versions below 2.0, using pointers to the global, local
+// and private address spaces.
+let MaxVersion = CL20 in {
+ foreach AS = [GlobalAS, LocalAS, PrivateAS] in {
+ foreach VSize = [2, 3, 4, 8, 16] in {
+ foreach name = ["vload" # VSize] in {
+ def : Builtin<name, [VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, AS>]>;
+ def : Builtin<name, [VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, AS>]>;
+ def : Builtin<name, [VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, AS>]>;
+ def : Builtin<name, [VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, AS>]>;
+ def : Builtin<name, [VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, AS>]>;
+ def : Builtin<name, [VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, AS>]>;
+ def : Builtin<name, [VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, AS>]>;
+ def : Builtin<name, [VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, AS>]>;
+ def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, AS>]>;
+ def : Builtin<name, [VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, AS>]>;
+ def : Builtin<name, [VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, AS>]>;
+ }
+ foreach name = ["vstore" # VSize] in {
+ def : Builtin<name, [Void, VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, AS>]>;
+ def : Builtin<name, [Void, VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, AS>]>;
+ def : Builtin<name, [Void, VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, AS>]>;
+ def : Builtin<name, [Void, VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, AS>]>;
+ def : Builtin<name, [Void, VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, AS>]>;
+ def : Builtin<name, [Void, VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, AS>]>;
+ def : Builtin<name, [Void, VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, AS>]>;
+ def : Builtin<name, [Void, VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, AS>]>;
+ def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, AS>]>;
+ def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, AS>]>;
+ def : Builtin<name, [Void, VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, AS>]>;
+ }
+ foreach name = ["vloada_half" # VSize] in {
+ def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>;
+ }
+ foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in {
+ foreach name = ["vstorea_half" # VSize # rnd] in {
+ def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, AS>]>;
+ def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Half, AS>]>;
+ }
+ }
+ }
+ }
+}
+// Variants for OpenCL versions above 2.0, using pointers to the generic
+// address space.
+let MinVersion = CL20 in {
+ foreach VSize = [2, 3, 4, 8, 16] in {
+ foreach name = ["vload" # VSize] in {
+ def : Builtin<name, [VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, GenericAS>]>;
+ def : Builtin<name, [VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, GenericAS>]>;
+ def : Builtin<name, [VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, GenericAS>]>;
+ def : Builtin<name, [VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, GenericAS>]>;
+ def : Builtin<name, [VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, GenericAS>]>;
+ def : Builtin<name, [VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, GenericAS>]>;
+ def : Builtin<name, [VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, GenericAS>]>;
+ def : Builtin<name, [VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, GenericAS>]>;
+ def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, GenericAS>]>;
+ def : Builtin<name, [VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, GenericAS>]>;
+ def : Builtin<name, [VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, GenericAS>]>;
+ }
+ foreach name = ["vstore" # VSize] in {
+ def : Builtin<name, [Void, VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, GenericAS>]>;
+ }
+ foreach name = ["vloada_half" # VSize] in {
+ def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, GenericAS>]>;
+ }
+ foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in {
+ foreach name = ["vstorea_half" # VSize # rnd] in {
+ def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Half, GenericAS>]>;
+ }
+ }
+ }
+}
+// Variants using pointers to the constant address space.
+foreach VSize = [2, 3, 4, 8, 16] in {
+ foreach name = ["vload" # VSize] in {
+ def : Builtin<name, [VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, ConstantAS>]>;
+ }
+ foreach name = ["vloada_half" # VSize] in {
+ def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, ConstantAS>]>;
+ }
+ foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in {
+ foreach name = ["vstorea_half" # VSize # rnd] in {
+ def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, ConstantAS>]>;
+ def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Half, ConstantAS>]>;
+ }
+ }
+}
+
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.10, v1.2 s6.12.10, v2.0 s6.13.10: Async Copies from Global to Local Memory, Local to Global Memory, and Prefetch
+// OpenCL Extension v2.0 s5.1.7 and s6.1.7: Async Copies from Global to Local Memory, Local to Global Memory, and Prefetch
+// --- Table 18 ---
+foreach name = ["async_work_group_copy"] in {
+ def : Builtin<name, [Event, PointerType<AGenTypeN, LocalAS>, PointerType<ConstType<AGenTypeN>, GlobalAS>, Size, Event]>;
+ def : Builtin<name, [Event, PointerType<AGenTypeN, GlobalAS>, PointerType<ConstType<AGenTypeN>, LocalAS>, Size, Event]>;
+}
+foreach name = ["async_work_group_strided_copy"] in {
+ def : Builtin<name, [Event, PointerType<AGenTypeN, LocalAS>, PointerType<ConstType<AGenTypeN>, GlobalAS>, Size, Size, Event]>;
+ def : Builtin<name, [Event, PointerType<AGenTypeN, GlobalAS>, PointerType<ConstType<AGenTypeN>, LocalAS>, Size, Size, Event]>;
+}
+foreach name = ["wait_group_events"] in {
+ def : Builtin<name, [Void, Int, PointerType<Event, GenericAS>]>;
+}
+foreach name = ["prefetch"] in {
+ def : Builtin<name, [Void, PointerType<ConstType<AGenTypeN>, GlobalAS>, Size]>;
+}
+
+//--------------------------------------------------------------------
+// OpenCL v2.0 s6.13.11 - Atomics Functions.
+// Functions that use memory_order and cl_mem_fence_flags enums are not
+// declared here as the TableGen backend does not handle enums.
+
+// OpenCL v1.0 s9.5, s9.6, s9.7 - Atomic Functions for 32-bit integers.
+// --- Table 9.1 ---
+foreach Type = [Int, UInt] in {
+ foreach name = ["atom_add", "atom_sub", "atom_xchg"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type]>;
+ }
+ foreach name = ["atom_inc", "atom_dec"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>]>;
+ }
+ foreach name = ["atom_cmpxchg"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type, Type]>;
+ }
}
// OpenCL v1.2 s6.12.2: Math Functions
foreach name = ["acos", "acosh", "acospi",
"asin", "asinh", "asinpi",
"atan", "atanh", "atanpi"] in {
- foreach type = [float_t, double_t, half_t] in {
- defm : Bif1<name, [type, type], [1, 1]>;
- }
+ def : Builtin<name, [FGenTypeN, FGenTypeN]>;
}
foreach name = ["atan2", "atan2pi"] in {
- foreach type = [float_t, double_t, half_t] in {
- defm : Bif2<name, [type, type, type], [1, 1, 1]>;
- }
+ def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN]>;
}
foreach name = ["fmax", "fmin"] in {
- foreach type = [float_t, double_t, half_t] in {
- defm : Bif2<name, [type, type, type], [1, 1, 1]>;
- defm : Bif2<name, [type, type, type], [1, 1, 0]>;
+ def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN]>;
+ def : Builtin<name, [GenTypeFloatVecNoScalar, GenTypeFloatVecNoScalar, Float]>;
+ def : Builtin<name, [GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar, Double]>;
+ def : Builtin<name, [GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar, Half]>;
+}
+
+// OpenCL v1.1 s6.11.3, v1.2 s6.12.3, v2.0 s6.13.3 - Integer Functions
+foreach name = ["max", "min"] in {
+ def : Builtin<name, [AIGenTypeN, AIGenTypeN, AIGenTypeN]>;
+ def : Builtin<name, [AIGenTypeNNoScalar, AIGenTypeNNoScalar, AIGenType1]>;
+}
+
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.3, v1.2 s6.12.14, v2.0 s6.13.14: Image Read and Write Functions
+// OpenCL Extension v2.0 s5.1.8 and s6.1.8: Image Read and Write Functions
+// --- Table 22: Image Read Functions with Samplers ---
+foreach imgTy = [Image1d] in {
+ foreach coordTy = [Int, Float] in {
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, coordTy]>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, coordTy]>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, coordTy]>;
+ }
+}
+foreach imgTy = [Image2d, Image1dArray] in {
+ foreach coordTy = [Int, Float] in {
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>]>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>]>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>]>;
}
}
+foreach imgTy = [Image3d, Image2dArray] in {
+ foreach coordTy = [Int, Float] in {
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>]>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>]>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>]>;
+ }
+}
+foreach coordTy = [Int, Float] in {
+ def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, "RO">, Sampler, VectorType<coordTy, 2>]>;
+ def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, "RO">, Sampler, VectorType<coordTy, 4>]>;
+}
-// OpenCL v1.2 s6.12.14: Built-in Image Read Functions
-def read_imagef : Builtin<"read_imagef",
- [float4_t, image2d_RO_t, VectorType<int_t, 2>]>;
-def write_imagef : Builtin<"write_imagef",
- [void_t,
- image2d_WO_t,
- VectorType<int_t, 2>,
- VectorType<float_t, 4>]>;
+// --- Table 23: Sampler-less Read Functions ---
+foreach aQual = ["RO", "RW"] in {
+ foreach imgTy = [Image2d, Image1dArray] in {
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
+ }
+ foreach imgTy = [Image3d, Image2dArray] in {
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
+ }
+ foreach imgTy = [Image1d, Image1dBuffer] in {
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, Int]>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, Int]>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Int]>;
+ }
+ def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>]>;
+ def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>]>;
+}
+
+// --- Table 24: Image Write Functions ---
+foreach aQual = ["WO", "RW"] in {
+ foreach imgTy = [Image2d] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<UInt, 4>]>;
+ }
+ foreach imgTy = [Image2dArray] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<UInt, 4>]>;
+ }
+ foreach imgTy = [Image1d, Image1dBuffer] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, Int, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, Int, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, Int, VectorType<UInt, 4>]>;
+ }
+ foreach imgTy = [Image1dArray] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<UInt, 4>]>;
+ }
+ foreach imgTy = [Image3d] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<UInt, 4>]>;
+ }
+ def : Builtin<"write_imagef", [Void, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>, Float]>;
+ def : Builtin<"write_imagef", [Void, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>, Float]>;
+}
+
+// --- Table 25: Image Query Functions ---
+foreach aQual = ["RO", "WO", "RW"] in {
+ foreach imgTy = [Image1d, Image1dBuffer, Image2d, Image3d,
+ Image1dArray, Image2dArray, Image2dDepth,
+ Image2dArrayDepth] in {
+ foreach name = ["get_image_width", "get_image_channel_data_type",
+ "get_image_channel_order"] in {
+ def : Builtin<name, [Int, ImageType<imgTy, aQual>]>;
+ }
+ }
+ foreach imgTy = [Image2d, Image3d, Image2dArray, Image2dDepth,
+ Image2dArrayDepth] in {
+ def : Builtin<"get_image_height", [Int, ImageType<imgTy, aQual>]>;
+ }
+ def : Builtin<"get_image_depth", [Int, ImageType<Image3d, aQual>]>;
+ foreach imgTy = [Image2d, Image2dArray, Image2dDepth,
+ Image2dArrayDepth] in {
+ def : Builtin<"get_image_dim", [VectorType<Int, 2>, ImageType<imgTy, aQual>]>;
+ }
+ def : Builtin<"get_image_dim", [VectorType<Int, 4>, ImageType<Image3d, aQual>]>;
+ foreach imgTy = [Image1dArray, Image2dArray, Image2dArrayDepth] in {
+ def : Builtin<"get_image_array_size", [Size, ImageType<imgTy, aQual>]>;
+ }
+}
+
+// OpenCL extension v2.0 s5.1.9: Built-in Image Read Functions
+// --- Table 8 ---
+foreach aQual = ["RO"] in {
+ foreach name = ["read_imageh"] in {
+ foreach coordTy = [Int, Float] in {
+ foreach imgTy = [Image2d, Image1dArray] in {
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 2>]>;
+ }
+ foreach imgTy = [Image3d, Image2dArray] in {
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 4>]>;
+ }
+ foreach imgTy = [Image1d] in {
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, coordTy]>;
+ }
+ }
+ }
+}
+// OpenCL extension v2.0 s5.1.10: Built-in Image Sampler-less Read Functions
+// --- Table 9 ---
+foreach aQual = ["RO", "RW"] in {
+ foreach name = ["read_imageh"] in {
+ foreach imgTy = [Image2d, Image1dArray] in {
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
+ }
+ foreach imgTy = [Image3d, Image2dArray] in {
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
+ }
+ foreach imgTy = [Image1d, Image1dBuffer] in {
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Int]>;
+ }
+ }
+}
+// OpenCL extension v2.0 s5.1.11: Built-in Image Write Functions
+// --- Table 10 ---
+foreach aQual = ["WO", "RW"] in {
+ foreach name = ["write_imageh"] in {
+ def : Builtin<name, [Void, ImageType<Image2d, aQual>, VectorType<Int, 2>, VectorType<Half, 4>]>;
+ def : Builtin<name, [Void, ImageType<Image2dArray, aQual>, VectorType<Int, 4>, VectorType<Half, 4>]>;
+ def : Builtin<name, [Void, ImageType<Image1d, aQual>, Int, VectorType<Half, 4>]>;
+ def : Builtin<name, [Void, ImageType<Image1dBuffer, aQual>, Int, VectorType<Half, 4>]>;
+ def : Builtin<name, [Void, ImageType<Image1dArray, aQual>, VectorType<Int, 2>, VectorType<Half, 4>]>;
+ def : Builtin<name, [Void, ImageType<Image3d, aQual>, VectorType<Int, 4>, VectorType<Half, 4>]>;
+ }
+}
// OpenCL v2.0 s9.17.3: Additions to section 6.13.1: Work-Item Functions
-let Version = CL20 in {
+let MinVersion = CL20 in {
let Extension = "cl_khr_subgroups" in {
- def get_sub_group_size : Builtin<"get_sub_group_size", [uint_t]>;
- def get_max_sub_group_size : Builtin<"get_max_sub_group_size", [uint_t]>;
- def get_num_sub_groups : Builtin<"get_num_sub_groups", [uint_t]>;
+ def get_sub_group_size : Builtin<"get_sub_group_size", [UInt]>;
+ def get_max_sub_group_size : Builtin<"get_max_sub_group_size", [UInt]>;
+ def get_num_sub_groups : Builtin<"get_num_sub_groups", [UInt]>;
}
}
diff --git a/lib/Sema/ParsedAttr.cpp b/lib/Sema/ParsedAttr.cpp
index 5c04443460bc..5d0a734f237a 100644
--- a/lib/Sema/ParsedAttr.cpp
+++ b/lib/Sema/ParsedAttr.cpp
@@ -100,71 +100,6 @@ void AttributePool::takePool(AttributePool &pool) {
pool.Attrs.clear();
}
-#include "clang/Sema/AttrParsedAttrKinds.inc"
-
-static StringRef normalizeAttrScopeName(StringRef ScopeName,
- ParsedAttr::Syntax SyntaxUsed) {
- // Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name
- // to be "clang".
- if (SyntaxUsed == ParsedAttr::AS_CXX11 ||
- SyntaxUsed == ParsedAttr::AS_C2x) {
- if (ScopeName == "__gnu__")
- ScopeName = "gnu";
- else if (ScopeName == "_Clang")
- ScopeName = "clang";
- }
- return ScopeName;
-}
-
-static StringRef normalizeAttrName(StringRef AttrName,
- StringRef NormalizedScopeName,
- ParsedAttr::Syntax SyntaxUsed) {
- // Normalize the attribute name, __foo__ becomes foo. This is only allowable
- // for GNU attributes, and attributes using the double square bracket syntax.
- bool ShouldNormalize =
- SyntaxUsed == ParsedAttr::AS_GNU ||
- ((SyntaxUsed == ParsedAttr::AS_CXX11 ||
- SyntaxUsed == ParsedAttr::AS_C2x) &&
- (NormalizedScopeName == "gnu" || NormalizedScopeName == "clang"));
- if (ShouldNormalize && AttrName.size() >= 4 && AttrName.startswith("__") &&
- AttrName.endswith("__"))
- AttrName = AttrName.slice(2, AttrName.size() - 2);
-
- return AttrName;
-}
-
-ParsedAttr::Kind ParsedAttr::getKind(const IdentifierInfo *Name,
- const IdentifierInfo *ScopeName,
- Syntax SyntaxUsed) {
- StringRef AttrName = Name->getName();
-
- SmallString<64> FullName;
- if (ScopeName)
- FullName += normalizeAttrScopeName(ScopeName->getName(), SyntaxUsed);
-
- AttrName = normalizeAttrName(AttrName, FullName, SyntaxUsed);
-
- // Ensure that in the case of C++11 attributes, we look for '::foo' if it is
- // unscoped.
- if (ScopeName || SyntaxUsed == AS_CXX11 || SyntaxUsed == AS_C2x)
- FullName += "::";
- FullName += AttrName;
-
- return ::getAttrKind(FullName, SyntaxUsed);
-}
-
-unsigned ParsedAttr::getAttributeSpellingListIndex() const {
- // Both variables will be used in tablegen generated
- // attribute spell list index matching code.
- auto Syntax = static_cast<ParsedAttr::Syntax>(SyntaxUsed);
- StringRef Scope =
- ScopeName ? normalizeAttrScopeName(ScopeName->getName(), Syntax) : "";
- StringRef Name = normalizeAttrName(AttrName->getName(), Scope, Syntax);
-
-#include "clang/Sema/AttrSpellingListIndex.inc"
-
-}
-
struct ParsedAttrInfo {
unsigned NumArgs : 4;
unsigned OptArgs : 4;
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 11fed28b52db..bedea2167950 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/Stack.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
@@ -37,6 +38,7 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/TemplateInstCallback.h"
+#include "clang/Sema/TypoCorrection.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/TimeProfiler.h"
@@ -181,7 +183,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
InitDataSharingAttributesStack();
std::unique_ptr<sema::SemaPPCallbacks> Callbacks =
- llvm::make_unique<sema::SemaPPCallbacks>();
+ std::make_unique<sema::SemaPPCallbacks>();
SemaPPCallbackHandler = Callbacks.get();
PP.addPPCallbacks(std::move(Callbacks));
SemaPPCallbackHandler->set(*this);
@@ -335,7 +337,13 @@ void Sema::Initialize() {
addImplicitTypedef(#ExtType, Context.Id##Ty); \
setOpenCLExtensionForType(Context.Id##Ty, #Ext);
#include "clang/Basic/OpenCLExtensionTypes.def"
- };
+ }
+
+ if (Context.getTargetInfo().hasAArch64SVETypes()) {
+#define SVE_TYPE(Name, Id, SingletonId) \
+ addImplicitTypedef(Name, Context.SingletonId);
+#include "clang/Basic/AArch64SVEACLETypes.def"
+ }
if (Context.getTargetInfo().hasBuiltinMSVaList()) {
DeclarationName MSVaList = &Context.Idents.get("__builtin_ms_va_list");
@@ -376,8 +384,19 @@ Sema::~Sema() {
// Detach from the PP callback handler which outlives Sema since it's owned
// by the preprocessor.
SemaPPCallbackHandler->reset();
+}
+
+void Sema::warnStackExhausted(SourceLocation Loc) {
+ // Only warn about this once.
+ if (!WarnedStackExhausted) {
+ Diag(Loc, diag::warn_stack_exhausted);
+ WarnedStackExhausted = true;
+ }
+}
- assert(DelayedTypos.empty() && "Uncorrected typos!");
+void Sema::runWithSufficientStackSpace(SourceLocation Loc,
+ llvm::function_ref<void()> Fn) {
+ clang::runWithSufficientStackSpace([&] { warnStackExhausted(Loc); }, Fn);
}
/// makeUnavailableInSystemHeader - There is an error in the current
@@ -907,9 +926,22 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) {
PerformPendingInstantiations();
}
+ // Finalize analysis of OpenMP-specific constructs.
+ if (LangOpts.OpenMP)
+ finalizeOpenMPDelayedAnalysis();
+
assert(LateParsedInstantiations.empty() &&
"end of TU template instantiation should not create more "
"late-parsed templates");
+
+ // Report diagnostics for uncorrected delayed typos. Ideally all of them
+ // should have been corrected by that time, but it is very hard to cover all
+ // cases in practice.
+ for (const auto &Typo : DelayedTypos) {
+ // We pass an empty TypoCorrection to indicate no correction was performed.
+ Typo.second.DiagHandler(TypoCorrection());
+ }
+ DelayedTypos.clear();
}
/// ActOnEndOfTranslationUnit - This is called at the very end of the
@@ -961,6 +993,7 @@ void Sema::ActOnEndOfTranslationUnit() {
// All dllexport classes should have been processed already.
assert(DelayedDllExportClasses.empty());
+ assert(DelayedDllExportMemberFunctions.empty());
// Remove file scoped decls that turned out to be used.
UnusedFileScopedDecls.erase(
@@ -1086,8 +1119,8 @@ void Sema::ActOnEndOfTranslationUnit() {
// Set the length of the array to 1 (C99 6.9.2p5).
Diag(VD->getLocation(), diag::warn_tentative_incomplete_array);
llvm::APInt One(Context.getTypeSize(Context.getSizeType()), true);
- QualType T = Context.getConstantArrayType(ArrayT->getElementType(),
- One, ArrayType::Normal, 0);
+ QualType T = Context.getConstantArrayType(ArrayT->getElementType(), One,
+ nullptr, ArrayType::Normal, 0);
VD->setType(T);
} else if (RequireCompleteType(VD->getLocation(), VD->getType(),
diag::err_tentative_def_incomplete_type))
@@ -1282,7 +1315,7 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
PartialDiagnostic(DiagInfo, Context.getDiagAllocator()));
}
- Diags.setLastDiagnosticIgnored();
+ Diags.setLastDiagnosticIgnored(true);
Diags.Clear();
return;
@@ -1307,7 +1340,7 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
PartialDiagnostic(DiagInfo, Context.getDiagAllocator()));
}
- Diags.setLastDiagnosticIgnored();
+ Diags.setLastDiagnosticIgnored(true);
Diags.Clear();
// Now the diagnostic state is clear, produce a C++98 compatibility
@@ -1316,7 +1349,7 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
// The last diagnostic which Sema produced was ignored. Suppress any
// notes attached to it.
- Diags.setLastDiagnosticIgnored();
+ Diags.setLastDiagnosticIgnored(true);
return;
}
@@ -1330,7 +1363,7 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
}
// Suppress this diagnostic.
- Diags.setLastDiagnosticIgnored();
+ Diags.setLastDiagnosticIgnored(true);
Diags.Clear();
return;
}
@@ -1376,7 +1409,7 @@ static void emitCallStackNotes(Sema &S, FunctionDecl *FD) {
// Emit any deferred diagnostics for FD and erase them from the map in which
// they're stored.
-static void emitDeferredDiags(Sema &S, FunctionDecl *FD) {
+static void emitDeferredDiags(Sema &S, FunctionDecl *FD, bool ShowCallStack) {
auto It = S.DeviceDeferredDiags.find(FD);
if (It == S.DeviceDeferredDiags.end())
return;
@@ -1395,7 +1428,7 @@ static void emitDeferredDiags(Sema &S, FunctionDecl *FD) {
// FIXME: Should this be called after every warning/error emitted in the loop
// above, instead of just once per function? That would be consistent with
// how we handle immediate errors, but it also seems like a bit much.
- if (HasWarningOrError)
+ if (HasWarningOrError && ShowCallStack)
emitCallStackNotes(S, FD);
}
@@ -1498,7 +1531,7 @@ void Sema::markKnownEmitted(
assert(!IsKnownEmitted(S, C.Callee) &&
"Worklist should not contain known-emitted functions.");
S.DeviceKnownEmittedFns[C.Callee] = {C.Caller, C.Loc};
- emitDeferredDiags(S, C.Callee);
+ emitDeferredDiags(S, C.Callee, C.Caller);
// If this is a template instantiation, explore its callgraph as well:
// Non-dependent calls are part of the template's callgraph, while dependent
@@ -1535,8 +1568,9 @@ void Sema::markKnownEmitted(
}
Sema::DeviceDiagBuilder Sema::targetDiag(SourceLocation Loc, unsigned DiagID) {
- if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)
- return diagIfOpenMPDeviceCode(Loc, DiagID);
+ if (LangOpts.OpenMP)
+ return LangOpts.OpenMPIsDevice ? diagIfOpenMPDeviceCode(Loc, DiagID)
+ : diagIfOpenMPHostCode(Loc, DiagID);
if (getLangOpts().CUDA)
return getLangOpts().CUDAIsDevice ? CUDADiagIfDeviceCode(Loc, DiagID)
: CUDADiagIfHostCode(Loc, DiagID);
@@ -1790,6 +1824,22 @@ FunctionScopeInfo *Sema::getEnclosingFunction() const {
return nullptr;
}
+LambdaScopeInfo *Sema::getEnclosingLambda() const {
+ for (auto *Scope : llvm::reverse(FunctionScopes)) {
+ if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Scope)) {
+ if (LSI->Lambda && !LSI->Lambda->Encloses(CurContext)) {
+ // We have switched contexts due to template instantiation.
+ // FIXME: We should swap out the FunctionScopes during code synthesis
+ // so that we don't need to check for this.
+ assert(!CodeSynthesisContexts.empty());
+ return nullptr;
+ }
+ return LSI;
+ }
+ }
+ return nullptr;
+}
+
LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) {
if (FunctionScopes.empty())
return nullptr;
@@ -1812,6 +1862,7 @@ LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) {
return CurLSI;
}
+
// We have a generic lambda if we parsed auto parameters, or we have
// an associated template parameter list.
LambdaScopeInfo *Sema::getCurGenericLambda() {
@@ -1934,11 +1985,9 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy,
// member templates with defaults/deduction of template arguments, overloads
// with default arguments, etc.
if (IsMemExpr && !E.isTypeDependent()) {
- bool Suppress = getDiagnostics().getSuppressAllDiagnostics();
- getDiagnostics().setSuppressAllDiagnostics(true);
+ Sema::TentativeAnalysisScope Trap(*this);
ExprResult R = BuildCallToMemberFunction(nullptr, &E, SourceLocation(),
None, SourceLocation());
- getDiagnostics().setSuppressAllDiagnostics(Suppress);
if (R.isUsable()) {
ZeroArgCallReturnTy = R.get()->getType();
return true;
@@ -2112,10 +2161,12 @@ IdentifierInfo *Sema::getFloat128Identifier() const {
}
void Sema::PushCapturedRegionScope(Scope *S, CapturedDecl *CD, RecordDecl *RD,
- CapturedRegionKind K) {
- CapturingScopeInfo *CSI = new CapturedRegionScopeInfo(
+ CapturedRegionKind K,
+ unsigned OpenMPCaptureLevel) {
+ auto *CSI = new CapturedRegionScopeInfo(
getDiagnostics(), S, CD, RD, CD->getContextParam(), K,
- (getLangOpts().OpenMP && K == CR_OpenMP) ? getOpenMPNestingLevel() : 0);
+ (getLangOpts().OpenMP && K == CR_OpenMP) ? getOpenMPNestingLevel() : 0,
+ OpenMPCaptureLevel);
CSI->ReturnType = Context.VoidTy;
FunctionScopes.push_back(CSI);
}
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index b6fbbbff91f5..9dbb93322b7d 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -1551,7 +1551,7 @@ Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
QualType BaseType = E->getBaseType();
if (E->isArrow())
- BaseType = BaseType->getAs<PointerType>()->getPointeeType();
+ BaseType = BaseType->castAs<PointerType>()->getPointeeType();
AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),
Found, BaseType);
@@ -1834,8 +1834,8 @@ Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
return AR_accessible;
CXXRecordDecl *BaseD, *DerivedD;
- BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
- DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
+ BaseD = cast<CXXRecordDecl>(Base->castAs<RecordType>()->getDecl());
+ DerivedD = cast<CXXRecordDecl>(Derived->castAs<RecordType>()->getDecl());
AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD,
Path.Access);
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 8e9318847373..70186c966f8f 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -85,6 +85,123 @@ void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) {
MSVtorDispAttr::CreateImplicit(Context, VtorDispStack.CurrentValue));
}
+template <typename Attribute>
+static void addGslOwnerPointerAttributeIfNotExisting(ASTContext &Context,
+ CXXRecordDecl *Record) {
+ if (Record->hasAttr<OwnerAttr>() || Record->hasAttr<PointerAttr>())
+ return;
+
+ for (Decl *Redecl : Record->redecls())
+ Redecl->addAttr(Attribute::CreateImplicit(Context, /*DerefType=*/nullptr));
+}
+
+void Sema::inferGslPointerAttribute(NamedDecl *ND,
+ CXXRecordDecl *UnderlyingRecord) {
+ if (!UnderlyingRecord)
+ return;
+
+ const auto *Parent = dyn_cast<CXXRecordDecl>(ND->getDeclContext());
+ if (!Parent)
+ return;
+
+ static llvm::StringSet<> Containers{
+ "array",
+ "basic_string",
+ "deque",
+ "forward_list",
+ "vector",
+ "list",
+ "map",
+ "multiset",
+ "multimap",
+ "priority_queue",
+ "queue",
+ "set",
+ "stack",
+ "unordered_set",
+ "unordered_map",
+ "unordered_multiset",
+ "unordered_multimap",
+ };
+
+ static llvm::StringSet<> Iterators{"iterator", "const_iterator",
+ "reverse_iterator",
+ "const_reverse_iterator"};
+
+ if (Parent->isInStdNamespace() && Iterators.count(ND->getName()) &&
+ Containers.count(Parent->getName()))
+ addGslOwnerPointerAttributeIfNotExisting<PointerAttr>(Context,
+ UnderlyingRecord);
+}
+
+void Sema::inferGslPointerAttribute(TypedefNameDecl *TD) {
+
+ QualType Canonical = TD->getUnderlyingType().getCanonicalType();
+
+ CXXRecordDecl *RD = Canonical->getAsCXXRecordDecl();
+ if (!RD) {
+ if (auto *TST =
+ dyn_cast<TemplateSpecializationType>(Canonical.getTypePtr())) {
+
+ RD = dyn_cast_or_null<CXXRecordDecl>(
+ TST->getTemplateName().getAsTemplateDecl()->getTemplatedDecl());
+ }
+ }
+
+ inferGslPointerAttribute(TD, RD);
+}
+
+void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
+ static llvm::StringSet<> StdOwners{
+ "any",
+ "array",
+ "basic_regex",
+ "basic_string",
+ "deque",
+ "forward_list",
+ "vector",
+ "list",
+ "map",
+ "multiset",
+ "multimap",
+ "optional",
+ "priority_queue",
+ "queue",
+ "set",
+ "stack",
+ "unique_ptr",
+ "unordered_set",
+ "unordered_map",
+ "unordered_multiset",
+ "unordered_multimap",
+ "variant",
+ };
+ static llvm::StringSet<> StdPointers{
+ "basic_string_view",
+ "reference_wrapper",
+ "regex_iterator",
+ };
+
+ if (!Record->getIdentifier())
+ return;
+
+ // Handle classes that directly appear in std namespace.
+ if (Record->isInStdNamespace()) {
+ if (Record->hasAttr<OwnerAttr>() || Record->hasAttr<PointerAttr>())
+ return;
+
+ if (StdOwners.count(Record->getName()))
+ addGslOwnerPointerAttributeIfNotExisting<OwnerAttr>(Context, Record);
+ else if (StdPointers.count(Record->getName()))
+ addGslOwnerPointerAttributeIfNotExisting<PointerAttr>(Context, Record);
+
+ return;
+ }
+
+ // Handle nested classes that could be a gsl::Pointer.
+ inferGslPointerAttribute(Record, Record);
+}
+
void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
SourceLocation PragmaLoc) {
PragmaMsStackAction Action = Sema::PSK_Reset;
@@ -149,6 +266,9 @@ void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionA
case PragmaClangSectionKind::PCSK_Rodata:
CSec = &PragmaClangRodataSection;
break;
+ case PragmaClangSectionKind::PCSK_Relro:
+ CSec = &PragmaClangRelroSection;
+ break;
case PragmaClangSectionKind::PCSK_Text:
CSec = &PragmaClangTextSection;
break;
@@ -454,12 +574,15 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
if (VD->isUsed())
Diag(PragmaLoc, diag::warn_used_but_marked_unused) << Name;
- VD->addAttr(UnusedAttr::CreateImplicit(Context, UnusedAttr::GNU_unused,
- IdTok.getLocation()));
+ VD->addAttr(UnusedAttr::CreateImplicit(Context, IdTok.getLocation(),
+ AttributeCommonInfo::AS_Pragma,
+ UnusedAttr::GNU_unused));
}
void Sema::AddCFAuditedAttribute(Decl *D) {
- SourceLocation Loc = PP.getPragmaARCCFCodeAuditedLoc();
+ IdentifierInfo *Ident;
+ SourceLocation Loc;
+ std::tie(Ident, Loc) = PP.getPragmaARCCFCodeAuditedInfo();
if (!Loc.isValid()) return;
// Don't add a redundant or conflicting attribute.
@@ -467,7 +590,9 @@ void Sema::AddCFAuditedAttribute(Decl *D) {
D->hasAttr<CFUnknownTransferAttr>())
return;
- D->addAttr(CFAuditedTransferAttr::CreateImplicit(Context, Loc));
+ AttributeCommonInfo Info(Ident, SourceRange(Loc),
+ AttributeCommonInfo::AS_Pragma);
+ D->addAttr(CFAuditedTransferAttr::CreateImplicit(Context, Info));
}
namespace {
@@ -618,7 +743,7 @@ void Sema::ActOnPragmaAttributeAttribute(
if (!Rules.empty()) {
auto Diagnostic =
Diag(PragmaLoc, diag::err_pragma_attribute_invalid_matchers)
- << Attribute.getName();
+ << Attribute;
SmallVector<attr::SubjectMatchRule, 2> ExtraRules;
for (const auto &Rule : Rules) {
ExtraRules.push_back(attr::SubjectMatchRule(Rule.first));
diff --git a/lib/Sema/SemaCUDA.cpp b/lib/Sema/SemaCUDA.cpp
index 203c09c57112..d0ddfd040c9c 100644
--- a/lib/Sema/SemaCUDA.cpp
+++ b/lib/Sema/SemaCUDA.cpp
@@ -267,6 +267,18 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
CXXMethodDecl *MemberDecl,
bool ConstRHS,
bool Diagnose) {
+ // If the defaulted special member is defined lexically outside of its
+ // owning class, or the special member already has explicit device or host
+ // attributes, do not infer.
+ bool InClass = MemberDecl->getLexicalParent() == MemberDecl->getParent();
+ bool HasH = MemberDecl->hasAttr<CUDAHostAttr>();
+ bool HasD = MemberDecl->hasAttr<CUDADeviceAttr>();
+ bool HasExplicitAttr =
+ (HasD && !MemberDecl->getAttr<CUDADeviceAttr>()->isImplicit()) ||
+ (HasH && !MemberDecl->getAttr<CUDAHostAttr>()->isImplicit());
+ if (!InClass || HasExplicitAttr)
+ return false;
+
llvm::Optional<CUDAFunctionTarget> InferredTarget;
// We're going to invoke special member lookup; mark that these special
@@ -371,21 +383,23 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
}
}
+
+ // If no target was inferred, mark this member as __host__ __device__;
+ // it's the least restrictive option that can be invoked from any target.
+ bool NeedsH = true, NeedsD = true;
if (InferredTarget.hasValue()) {
- if (InferredTarget.getValue() == CFT_Device) {
- MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
- } else if (InferredTarget.getValue() == CFT_Host) {
- MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
- } else {
- MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
- MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
- }
- } else {
- // If no target was inferred, mark this member as __host__ __device__;
- // it's the least restrictive option that can be invoked from any target.
+ if (InferredTarget.getValue() == CFT_Device)
+ NeedsH = false;
+ else if (InferredTarget.getValue() == CFT_Host)
+ NeedsD = false;
+ }
+
+ // We either setting attributes first time, or the inferred ones must match
+ // previously set ones.
+ if (NeedsD && !HasD)
MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
+ if (NeedsH && !HasH)
MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
- }
return false;
}
@@ -586,40 +600,6 @@ void Sema::maybeAddCUDAHostDeviceAttrs(FunctionDecl *NewD,
NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context));
}
-// Do we know that we will eventually codegen the given function?
-static bool IsKnownEmitted(Sema &S, FunctionDecl *FD) {
- // Templates are emitted when they're instantiated.
- if (FD->isDependentContext())
- return false;
-
- // When compiling for device, host functions are never emitted. Similarly,
- // when compiling for host, device and global functions are never emitted.
- // (Technically, we do emit a host-side stub for global functions, but this
- // doesn't count for our purposes here.)
- Sema::CUDAFunctionTarget T = S.IdentifyCUDATarget(FD);
- if (S.getLangOpts().CUDAIsDevice && T == Sema::CFT_Host)
- return false;
- if (!S.getLangOpts().CUDAIsDevice &&
- (T == Sema::CFT_Device || T == Sema::CFT_Global))
- return false;
-
- // Check whether this function is externally visible -- if so, it's
- // known-emitted.
- //
- // We have to check the GVA linkage of the function's *definition* -- if we
- // only have a declaration, we don't know whether or not the function will be
- // emitted, because (say) the definition could include "inline".
- FunctionDecl *Def = FD->getDefinition();
-
- if (Def &&
- !isDiscardableGVALinkage(S.getASTContext().GetGVALinkageForFunction(Def)))
- return true;
-
- // Otherwise, the function is known-emitted if it's in our set of
- // known-emitted functions.
- return S.DeviceKnownEmittedFns.count(FD) > 0;
-}
-
Sema::DeviceDiagBuilder Sema::CUDADiagIfDeviceCode(SourceLocation Loc,
unsigned DiagID) {
assert(getLangOpts().CUDA && "Should only be called during CUDA compilation");
@@ -633,7 +613,8 @@ Sema::DeviceDiagBuilder Sema::CUDADiagIfDeviceCode(SourceLocation Loc,
// device code if we're compiling for device. Defer any errors in device
// mode until the function is known-emitted.
if (getLangOpts().CUDAIsDevice) {
- return IsKnownEmitted(*this, dyn_cast<FunctionDecl>(CurContext))
+ return (getEmissionStatus(cast<FunctionDecl>(CurContext)) ==
+ FunctionEmissionStatus::Emitted)
? DeviceDiagBuilder::K_ImmediateWithCallStack
: DeviceDiagBuilder::K_Deferred;
}
@@ -661,7 +642,8 @@ Sema::DeviceDiagBuilder Sema::CUDADiagIfHostCode(SourceLocation Loc,
if (getLangOpts().CUDAIsDevice)
return DeviceDiagBuilder::K_Nop;
- return IsKnownEmitted(*this, dyn_cast<FunctionDecl>(CurContext))
+ return (getEmissionStatus(cast<FunctionDecl>(CurContext)) ==
+ FunctionEmissionStatus::Emitted)
? DeviceDiagBuilder::K_ImmediateWithCallStack
: DeviceDiagBuilder::K_Deferred;
default:
@@ -688,12 +670,16 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) {
// If the caller is known-emitted, mark the callee as known-emitted.
// Otherwise, mark the call in our call graph so we can traverse it later.
- bool CallerKnownEmitted = IsKnownEmitted(*this, Caller);
+ bool CallerKnownEmitted =
+ getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted;
if (CallerKnownEmitted) {
// Host-side references to a __global__ function refer to the stub, so the
// function itself is never emitted and therefore should not be marked.
- if (getLangOpts().CUDAIsDevice || IdentifyCUDATarget(Callee) != CFT_Global)
- markKnownEmitted(*this, Caller, Callee, Loc, IsKnownEmitted);
+ if (!shouldIgnoreInHostDeviceCheck(Callee))
+ markKnownEmitted(
+ *this, Caller, Callee, Loc, [](Sema &S, FunctionDecl *FD) {
+ return S.getEmissionStatus(FD) == FunctionEmissionStatus::Emitted;
+ });
} else {
// If we have
// host fn calls kernel fn calls host+device,
@@ -701,7 +687,7 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) {
// omitting at the call to the kernel from the callgraph. This ensures
// that, when compiling for host, only HD functions actually called from the
// host get marked as known-emitted.
- if (getLangOpts().CUDAIsDevice || IdentifyCUDATarget(Callee) != CFT_Global)
+ if (!shouldIgnoreInHostDeviceCheck(Callee))
DeviceCallGraph[Caller].insert({Callee, Loc});
}
@@ -806,7 +792,8 @@ void Sema::inheritCUDATargetAttrs(FunctionDecl *FD,
std::string Sema::getCudaConfigureFuncName() const {
if (getLangOpts().HIP)
- return "hipConfigureCall";
+ return getLangOpts().HIPUseNewLaunchAPI ? "__hipPushCallConfiguration"
+ : "hipConfigureCall";
// New CUDA kernel launch sequence.
if (CudaFeatureEnabled(Context.getTargetInfo().getSDKVersion(),
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index c473856f0b07..a4421d2b68af 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -440,7 +440,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<NestedNameSpecifierValidatorCCC>(*this);
+ return std::make_unique<NestedNameSpecifierValidatorCCC>(*this);
}
private:
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index f184eda2f273..0ebb5c68f7c2 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -1304,6 +1304,7 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
bool DerivedToBase;
bool ObjCConversion;
bool ObjCLifetimeConversion;
+ bool FunctionConversion;
QualType FromType = SrcExpr->getType();
QualType ToType = R->getPointeeType();
if (CStyle) {
@@ -1313,7 +1314,7 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
Sema::ReferenceCompareResult RefResult = Self.CompareReferenceRelationship(
SrcExpr->getBeginLoc(), ToType, FromType, DerivedToBase, ObjCConversion,
- ObjCLifetimeConversion);
+ ObjCLifetimeConversion, FunctionConversion);
if (RefResult != Sema::Ref_Compatible) {
if (CStyle || RefResult == Sema::Ref_Incompatible)
return TC_NotApplicable;
@@ -2799,6 +2800,15 @@ void CastOperation::CheckCStyleCast() {
void CastOperation::CheckBuiltinBitCast() {
QualType SrcType = SrcExpr.get()->getType();
+
+ if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
+ diag::err_typecheck_cast_to_incomplete) ||
+ Self.RequireCompleteType(OpRange.getBegin(), SrcType,
+ diag::err_incomplete_type)) {
+ SrcExpr = ExprError();
+ return;
+ }
+
if (SrcExpr.get()->isRValue())
SrcExpr = Self.CreateMaterializeTemporaryExpr(SrcType, SrcExpr.get(),
/*IsLValueReference=*/false);
@@ -2826,11 +2836,6 @@ void CastOperation::CheckBuiltinBitCast() {
return;
}
- if (Self.Context.hasSameUnqualifiedType(DestType, SrcType)) {
- Kind = CK_NoOp;
- return;
- }
-
Kind = CK_LValueToRValueBitCast;
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index f9f82cdeef43..dca81d1d275f 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -191,7 +191,7 @@ static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) {
return false;
}
-/// Check the number of arguments, and set the result type to
+/// Check the number of arguments and set the result type to
/// the argument type.
static bool SemaBuiltinPreserveAI(Sema &S, CallExpr *TheCall) {
if (checkArgCount(S, TheCall, 1))
@@ -484,7 +484,7 @@ static bool checkOpenCLBlockArgs(Sema &S, Expr *BlockArg) {
const BlockPointerType *BPT =
cast<BlockPointerType>(BlockArg->getType().getCanonicalType());
ArrayRef<QualType> Params =
- BPT->getPointeeType()->getAs<FunctionProtoType>()->getParamTypes();
+ BPT->getPointeeType()->castAs<FunctionProtoType>()->getParamTypes();
unsigned ArgCounter = 0;
bool IllegalParams = false;
// Iterate through the block parameters until either one is found that is not
@@ -583,7 +583,7 @@ static bool checkOpenCLEnqueueVariadicArgs(Sema &S, CallExpr *TheCall,
const BlockPointerType *BPT =
cast<BlockPointerType>(BlockArg->getType().getCanonicalType());
unsigned NumBlockParams =
- BPT->getPointeeType()->getAs<FunctionProtoType>()->getNumParams();
+ BPT->getPointeeType()->castAs<FunctionProtoType>()->getNumParams();
unsigned TotalNumArgs = TheCall->getNumArgs();
// For each argument passed to the block, a corresponding uint needs to
@@ -629,7 +629,9 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
unsigned NumArgs = TheCall->getNumArgs();
if (NumArgs < 4) {
- S.Diag(TheCall->getBeginLoc(), diag::err_typecheck_call_too_few_args);
+ S.Diag(TheCall->getBeginLoc(),
+ diag::err_typecheck_call_too_few_args_at_least)
+ << 0 << 4 << NumArgs;
return true;
}
@@ -674,7 +676,7 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
// we have a block type, check the prototype
const BlockPointerType *BPT =
cast<BlockPointerType>(Arg3->getType().getCanonicalType());
- if (BPT->getPointeeType()->getAs<FunctionProtoType>()->getNumParams() > 0) {
+ if (BPT->getPointeeType()->castAs<FunctionProtoType>()->getNumParams() > 0) {
S.Diag(Arg3->getBeginLoc(),
diag::err_opencl_enqueue_kernel_blocks_no_args);
return true;
@@ -1179,6 +1181,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BI__builtin_alloca_with_align:
if (SemaBuiltinAllocaWithAlign(TheCall))
return ExprError();
+ LLVM_FALLTHROUGH;
+ case Builtin::BI__builtin_alloca:
+ Diag(TheCall->getBeginLoc(), diag::warn_alloca)
+ << TheCall->getDirectCallee();
break;
case Builtin::BI__assume:
case Builtin::BI__builtin_assume:
@@ -1534,6 +1540,11 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();
break;
+ case llvm::Triple::bpfeb:
+ case llvm::Triple::bpfel:
+ if (CheckBPFBuiltinFunctionCall(BuiltinID, TheCall))
+ return ExprError();
+ break;
case llvm::Triple::hexagon:
if (CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();
@@ -1928,11 +1939,46 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
case AArch64::BI__builtin_arm_dmb:
case AArch64::BI__builtin_arm_dsb:
case AArch64::BI__builtin_arm_isb: l = 0; u = 15; break;
+ case AArch64::BI__builtin_arm_tcancel: l = 0; u = 65535; break;
}
return SemaBuiltinConstantArgRange(TheCall, i, l, u + l);
}
+bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID,
+ CallExpr *TheCall) {
+ assert(BuiltinID == BPF::BI__builtin_preserve_field_info &&
+ "unexpected ARM builtin");
+
+ if (checkArgCount(*this, TheCall, 2))
+ return true;
+
+ // The first argument needs to be a record field access.
+ // If it is an array element access, we delay decision
+ // to BPF backend to check whether the access is a
+ // field access or not.
+ Expr *Arg = TheCall->getArg(0);
+ if (Arg->getType()->getAsPlaceholderType() ||
+ (Arg->IgnoreParens()->getObjectKind() != OK_BitField &&
+ !dyn_cast<MemberExpr>(Arg->IgnoreParens()) &&
+ !dyn_cast<ArraySubscriptExpr>(Arg->IgnoreParens()))) {
+ Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_field)
+ << 1 << Arg->getSourceRange();
+ return true;
+ }
+
+ // The second argument needs to be a constant int
+ llvm::APSInt Value;
+ if (!TheCall->getArg(1)->isIntegerConstantExpr(Value, Context)) {
+ Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_const)
+ << 2 << Arg->getSourceRange();
+ return true;
+ }
+
+ TheCall->setType(Context.UnsignedIntTy);
+ return false;
+}
+
bool Sema::CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) {
struct BuiltinAndString {
unsigned BuiltinID;
@@ -3213,6 +3259,8 @@ bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case PPC::BI__builtin_altivec_crypto_vshasigmad:
return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) ||
SemaBuiltinConstantArgRange(TheCall, 2, 0, 15);
+ case PPC::BI__builtin_altivec_dss:
+ return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3);
case PPC::BI__builtin_tbegin:
case PPC::BI__builtin_tend: i = 0; l = 0; u = 1; break;
case PPC::BI__builtin_tsr: i = 0; l = 0; u = 7; break;
@@ -3222,6 +3270,11 @@ bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case PPC::BI__builtin_tabortdci:
return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) ||
SemaBuiltinConstantArgRange(TheCall, 2, 0, 31);
+ case PPC::BI__builtin_altivec_dst:
+ case PPC::BI__builtin_altivec_dstt:
+ case PPC::BI__builtin_altivec_dstst:
+ case PPC::BI__builtin_altivec_dststt:
+ return SemaBuiltinConstantArgRange(TheCall, 2, 0, 3);
case PPC::BI__builtin_vsx_xxpermdi:
case PPC::BI__builtin_vsx_xxsldwi:
return SemaBuiltinVSX(TheCall);
@@ -3532,9 +3585,11 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) {
// Make sure rounding mode is either ROUND_CUR_DIRECTION or ROUND_NO_EXC bit
// is set. If the intrinsic has rounding control(bits 1:0), make sure its only
- // combined with ROUND_NO_EXC.
+ // combined with ROUND_NO_EXC. If the intrinsic does not have rounding
+ // control, allow ROUND_NO_EXC and ROUND_CUR_DIRECTION together.
if (Result == 4/*ROUND_CUR_DIRECTION*/ ||
Result == 8/*ROUND_NO_EXC*/ ||
+ (!HasRC && Result == 12/*ROUND_CUR_DIRECTION|ROUND_NO_EXC*/) ||
(HasRC && Result.getZExtValue() >= 8 && Result.getZExtValue() <= 11))
return false;
@@ -4449,7 +4504,16 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
AtomicExpr::AtomicOp Op) {
CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+ MultiExprArg Args{TheCall->getArgs(), TheCall->getNumArgs()};
+ return BuildAtomicExpr({TheCall->getBeginLoc(), TheCall->getEndLoc()},
+ DRE->getSourceRange(), TheCall->getRParenLoc(), Args,
+ Op);
+}
+ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
+ SourceLocation RParenLoc, MultiExprArg Args,
+ AtomicExpr::AtomicOp Op,
+ AtomicArgumentOrder ArgOrder) {
// All the non-OpenCL operations take one of the following forms.
// The OpenCL operations take the __c11 forms with one extra argument for
// synchronization scope.
@@ -4596,21 +4660,21 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
if (IsOpenCL && Op != AtomicExpr::AO__opencl_atomic_init)
++AdjustedNumArgs;
// Check we have the right number of arguments.
- if (TheCall->getNumArgs() < AdjustedNumArgs) {
- Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args)
- << 0 << AdjustedNumArgs << TheCall->getNumArgs()
- << TheCall->getCallee()->getSourceRange();
+ if (Args.size() < AdjustedNumArgs) {
+ Diag(CallRange.getEnd(), diag::err_typecheck_call_too_few_args)
+ << 0 << AdjustedNumArgs << static_cast<unsigned>(Args.size())
+ << ExprRange;
return ExprError();
- } else if (TheCall->getNumArgs() > AdjustedNumArgs) {
- Diag(TheCall->getArg(AdjustedNumArgs)->getBeginLoc(),
+ } else if (Args.size() > AdjustedNumArgs) {
+ Diag(Args[AdjustedNumArgs]->getBeginLoc(),
diag::err_typecheck_call_too_many_args)
- << 0 << AdjustedNumArgs << TheCall->getNumArgs()
- << TheCall->getCallee()->getSourceRange();
+ << 0 << AdjustedNumArgs << static_cast<unsigned>(Args.size())
+ << ExprRange;
return ExprError();
}
// Inspect the first argument of the atomic operation.
- Expr *Ptr = TheCall->getArg(0);
+ Expr *Ptr = Args[0];
ExprResult ConvertedPtr = DefaultFunctionArrayLvalueConversion(Ptr);
if (ConvertedPtr.isInvalid())
return ExprError();
@@ -4618,7 +4682,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
Ptr = ConvertedPtr.get();
const PointerType *pointerType = Ptr->getType()->getAs<PointerType>();
if (!pointerType) {
- Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer)
+ Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer)
<< Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
@@ -4628,21 +4692,21 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
QualType ValType = AtomTy; // 'C'
if (IsC11) {
if (!AtomTy->isAtomicType()) {
- Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_atomic)
+ Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic)
<< Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
if ((Form != Load && Form != LoadCopy && AtomTy.isConstQualified()) ||
AtomTy.getAddressSpace() == LangAS::opencl_constant) {
- Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_non_const_atomic)
+ Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_non_const_atomic)
<< (AtomTy.isConstQualified() ? 0 : 1) << Ptr->getType()
<< Ptr->getSourceRange();
return ExprError();
}
- ValType = AtomTy->getAs<AtomicType>()->getValueType();
+ ValType = AtomTy->castAs<AtomicType>()->getValueType();
} else if (Form != Load && Form != LoadCopy) {
if (ValType.isConstQualified()) {
- Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_non_const_pointer)
+ Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_non_const_pointer)
<< Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
@@ -4653,7 +4717,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
// gcc does not enforce these rules for GNU atomics, but we do so for sanity.
if (IsAddSub && !ValType->isIntegerType()
&& !ValType->isPointerType()) {
- Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_atomic_int_or_ptr)
+ Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int_or_ptr)
<< IsC11 << Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
@@ -4661,12 +4725,12 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
const BuiltinType *BT = ValType->getAs<BuiltinType>();
if (!BT || (BT->getKind() != BuiltinType::Int &&
BT->getKind() != BuiltinType::UInt)) {
- Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_int32_or_ptr);
+ Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_int32_or_ptr);
return ExprError();
}
}
if (!IsAddSub && !IsMinMax && !ValType->isIntegerType()) {
- Diag(DRE->getBeginLoc(), diag::err_atomic_op_bitwise_needs_atomic_int)
+ Diag(ExprRange.getBegin(), diag::err_atomic_op_bitwise_needs_atomic_int)
<< IsC11 << Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
@@ -4678,7 +4742,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
} else if (IsN && !ValType->isIntegerType() && !ValType->isPointerType()) {
// For __atomic_*_n operations, the value type must be a scalar integral or
// pointer type which is 1, 2, 4, 8 or 16 bytes in length.
- Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_atomic_int_or_ptr)
+ Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int_or_ptr)
<< IsC11 << Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
@@ -4687,7 +4751,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
!AtomTy->isScalarType()) {
// For GNU atomics, require a trivially-copyable type. This is not part of
// the GNU atomics specification, but we enforce it for sanity.
- Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_trivial_copy)
+ Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_trivial_copy)
<< Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
@@ -4703,7 +4767,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
case Qualifiers::OCL_Autoreleasing:
// FIXME: Can this happen? By this point, ValType should be known
// to be trivially copyable.
- Diag(DRE->getBeginLoc(), diag::err_arc_atomic_ownership)
+ Diag(ExprRange.getBegin(), diag::err_arc_atomic_ownership)
<< ValType << Ptr->getSourceRange();
return ExprError();
}
@@ -4730,19 +4794,56 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
IsPassedByAddress = true;
}
+ SmallVector<Expr *, 5> APIOrderedArgs;
+ if (ArgOrder == Sema::AtomicArgumentOrder::AST) {
+ APIOrderedArgs.push_back(Args[0]);
+ switch (Form) {
+ case Init:
+ case Load:
+ APIOrderedArgs.push_back(Args[1]); // Val1/Order
+ break;
+ case LoadCopy:
+ case Copy:
+ case Arithmetic:
+ case Xchg:
+ APIOrderedArgs.push_back(Args[2]); // Val1
+ APIOrderedArgs.push_back(Args[1]); // Order
+ break;
+ case GNUXchg:
+ APIOrderedArgs.push_back(Args[2]); // Val1
+ APIOrderedArgs.push_back(Args[3]); // Val2
+ APIOrderedArgs.push_back(Args[1]); // Order
+ break;
+ case C11CmpXchg:
+ APIOrderedArgs.push_back(Args[2]); // Val1
+ APIOrderedArgs.push_back(Args[4]); // Val2
+ APIOrderedArgs.push_back(Args[1]); // Order
+ APIOrderedArgs.push_back(Args[3]); // OrderFail
+ break;
+ case GNUCmpXchg:
+ APIOrderedArgs.push_back(Args[2]); // Val1
+ APIOrderedArgs.push_back(Args[4]); // Val2
+ APIOrderedArgs.push_back(Args[5]); // Weak
+ APIOrderedArgs.push_back(Args[1]); // Order
+ APIOrderedArgs.push_back(Args[3]); // OrderFail
+ break;
+ }
+ } else
+ APIOrderedArgs.append(Args.begin(), Args.end());
+
// The first argument's non-CV pointer type is used to deduce the type of
// subsequent arguments, except for:
// - weak flag (always converted to bool)
// - memory order (always converted to int)
// - scope (always converted to int)
- for (unsigned i = 0; i != TheCall->getNumArgs(); ++i) {
+ for (unsigned i = 0; i != APIOrderedArgs.size(); ++i) {
QualType Ty;
if (i < NumVals[Form] + 1) {
switch (i) {
case 0:
// The first argument is always a pointer. It has a fixed type.
// It is always dereferenced, a nullptr is undefined.
- CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getBeginLoc());
+ CheckNonNullArgument(*this, APIOrderedArgs[i], ExprRange.getBegin());
// Nothing else to do: we already know all we want about this pointer.
continue;
case 1:
@@ -4754,16 +4855,18 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
if (Form == Init || (Form == Arithmetic && ValType->isIntegerType()))
Ty = ValType;
else if (Form == Copy || Form == Xchg) {
- if (IsPassedByAddress)
+ if (IsPassedByAddress) {
// The value pointer is always dereferenced, a nullptr is undefined.
- CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getBeginLoc());
+ CheckNonNullArgument(*this, APIOrderedArgs[i],
+ ExprRange.getBegin());
+ }
Ty = ByValType;
} else if (Form == Arithmetic)
Ty = Context.getPointerDiffType();
else {
- Expr *ValArg = TheCall->getArg(i);
+ Expr *ValArg = APIOrderedArgs[i];
// The value pointer is always dereferenced, a nullptr is undefined.
- CheckNonNullArgument(*this, ValArg, DRE->getBeginLoc());
+ CheckNonNullArgument(*this, ValArg, ExprRange.getBegin());
LangAS AS = LangAS::Default;
// Keep address space of non-atomic pointer type.
if (const PointerType *PtrTy =
@@ -4778,7 +4881,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
// The third argument to compare_exchange / GNU exchange is the desired
// value, either by-value (for the C11 and *_n variant) or as a pointer.
if (IsPassedByAddress)
- CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getBeginLoc());
+ CheckNonNullArgument(*this, APIOrderedArgs[i], ExprRange.getBegin());
Ty = ByValType;
break;
case 3:
@@ -4793,11 +4896,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
InitializedEntity Entity =
InitializedEntity::InitializeParameter(Context, Ty, false);
- ExprResult Arg = TheCall->getArg(i);
+ ExprResult Arg = APIOrderedArgs[i];
Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
if (Arg.isInvalid())
return true;
- TheCall->setArg(i, Arg.get());
+ APIOrderedArgs[i] = Arg.get();
}
// Permute the arguments into a 'consistent' order.
@@ -4806,36 +4909,36 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
switch (Form) {
case Init:
// Note, AtomicExpr::getVal1() has a special case for this atomic.
- SubExprs.push_back(TheCall->getArg(1)); // Val1
+ SubExprs.push_back(APIOrderedArgs[1]); // Val1
break;
case Load:
- SubExprs.push_back(TheCall->getArg(1)); // Order
+ SubExprs.push_back(APIOrderedArgs[1]); // Order
break;
case LoadCopy:
case Copy:
case Arithmetic:
case Xchg:
- SubExprs.push_back(TheCall->getArg(2)); // Order
- SubExprs.push_back(TheCall->getArg(1)); // Val1
+ SubExprs.push_back(APIOrderedArgs[2]); // Order
+ SubExprs.push_back(APIOrderedArgs[1]); // Val1
break;
case GNUXchg:
// Note, AtomicExpr::getVal2() has a special case for this atomic.
- SubExprs.push_back(TheCall->getArg(3)); // Order
- SubExprs.push_back(TheCall->getArg(1)); // Val1
- SubExprs.push_back(TheCall->getArg(2)); // Val2
+ SubExprs.push_back(APIOrderedArgs[3]); // Order
+ SubExprs.push_back(APIOrderedArgs[1]); // Val1
+ SubExprs.push_back(APIOrderedArgs[2]); // Val2
break;
case C11CmpXchg:
- SubExprs.push_back(TheCall->getArg(3)); // Order
- SubExprs.push_back(TheCall->getArg(1)); // Val1
- SubExprs.push_back(TheCall->getArg(4)); // OrderFail
- SubExprs.push_back(TheCall->getArg(2)); // Val2
+ SubExprs.push_back(APIOrderedArgs[3]); // Order
+ SubExprs.push_back(APIOrderedArgs[1]); // Val1
+ SubExprs.push_back(APIOrderedArgs[4]); // OrderFail
+ SubExprs.push_back(APIOrderedArgs[2]); // Val2
break;
case GNUCmpXchg:
- SubExprs.push_back(TheCall->getArg(4)); // Order
- SubExprs.push_back(TheCall->getArg(1)); // Val1
- SubExprs.push_back(TheCall->getArg(5)); // OrderFail
- SubExprs.push_back(TheCall->getArg(2)); // Val2
- SubExprs.push_back(TheCall->getArg(3)); // Weak
+ SubExprs.push_back(APIOrderedArgs[4]); // Order
+ SubExprs.push_back(APIOrderedArgs[1]); // Val1
+ SubExprs.push_back(APIOrderedArgs[5]); // OrderFail
+ SubExprs.push_back(APIOrderedArgs[2]); // Val2
+ SubExprs.push_back(APIOrderedArgs[3]); // Weak
break;
}
@@ -4849,7 +4952,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
}
if (auto ScopeModel = AtomicExpr::getScopeModel(Op)) {
- auto *Scope = TheCall->getArg(TheCall->getNumArgs() - 1);
+ auto *Scope = Args[Args.size() - 1];
llvm::APSInt Result(32);
if (Scope->isIntegerConstantExpr(Result, Context) &&
!ScopeModel->isValid(Result.getZExtValue())) {
@@ -4859,9 +4962,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
SubExprs.push_back(Scope);
}
- AtomicExpr *AE =
- new (Context) AtomicExpr(TheCall->getCallee()->getBeginLoc(), SubExprs,
- ResultType, Op, TheCall->getRParenLoc());
+ AtomicExpr *AE = new (Context)
+ AtomicExpr(ExprRange.getBegin(), SubExprs, ResultType, Op, RParenLoc);
if ((Op == AtomicExpr::AO__c11_atomic_load ||
Op == AtomicExpr::AO__c11_atomic_store ||
@@ -5410,7 +5512,7 @@ static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) {
if (IsX64 || IsAArch64) {
CallingConv CC = CC_C;
if (const FunctionDecl *FD = S.getCurFunctionDecl())
- CC = FD->getType()->getAs<FunctionType>()->getCallConv();
+ CC = FD->getType()->castAs<FunctionType>()->getCallConv();
if (IsMSVAStart) {
// Don't allow this in System V ABI functions.
if (CC == CC_X86_64SysV || (!IsWindows && CC != CC_Win64))
@@ -5540,7 +5642,7 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
return false;
if (!Type->isEnumeralType())
return true;
- const EnumDecl *ED = Type->getAs<EnumType>()->getDecl();
+ const EnumDecl *ED = Type->castAs<EnumType>()->getDecl();
return !(ED &&
Context.typesAreCompatible(ED->getPromotionType(), Type));
}()) {
@@ -5780,7 +5882,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc()));
- numElements = LHSType->getAs<VectorType>()->getNumElements();
+ numElements = LHSType->castAs<VectorType>()->getNumElements();
unsigned numResElements = TheCall->getNumArgs() - 2;
// Check to see if we have a call with 2 vector arguments, the unary shuffle
@@ -5788,7 +5890,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
// same number of elts as lhs.
if (TheCall->getNumArgs() == 2) {
if (!RHSType->hasIntegerRepresentation() ||
- RHSType->getAs<VectorType>()->getNumElements() != numElements)
+ RHSType->castAs<VectorType>()->getNumElements() != numElements)
return ExprError(Diag(TheCall->getBeginLoc(),
diag::err_vec_builtin_incompatible_vector)
<< TheCall->getDirectCallee()
@@ -5801,7 +5903,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc()));
} else if (numElements != numResElements) {
- QualType eltType = LHSType->getAs<VectorType>()->getElementType();
+ QualType eltType = LHSType->castAs<VectorType>()->getElementType();
resType = Context.getVectorType(eltType, numResElements,
VectorType::GenericVector);
}
@@ -5858,8 +5960,8 @@ ExprResult Sema::SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,
diag::err_convertvector_non_vector_type));
if (!SrcTy->isDependentType() && !DstTy->isDependentType()) {
- unsigned SrcElts = SrcTy->getAs<VectorType>()->getNumElements();
- unsigned DstElts = DstTy->getAs<VectorType>()->getNumElements();
+ unsigned SrcElts = SrcTy->castAs<VectorType>()->getNumElements();
+ unsigned DstElts = DstTy->castAs<VectorType>()->getNumElements();
if (SrcElts != DstElts)
return ExprError(Diag(BuiltinLoc,
diag::err_convertvector_incompatible_vector)
@@ -5961,6 +6063,12 @@ bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) {
if (!Result.isPowerOf2())
return Diag(TheCall->getBeginLoc(), diag::err_alignment_not_power_of_two)
<< Arg->getSourceRange();
+
+ // Alignment calculations can wrap around if it's greater than 2**29.
+ unsigned MaximumAlignment = 536870912;
+ if (Result > MaximumAlignment)
+ Diag(TheCall->getBeginLoc(), diag::warn_assume_aligned_too_great)
+ << Arg->getSourceRange() << MaximumAlignment;
}
if (NumArgs > 2) {
@@ -6570,7 +6678,8 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr,
bool inFunctionCall,
Sema::VariadicCallType CallType,
llvm::SmallBitVector &CheckedVarArgs,
- UncoveredArgHandler &UncoveredArg);
+ UncoveredArgHandler &UncoveredArg,
+ bool IgnoreStringsWithoutSpecifiers);
// Determine if an expression is a string literal or constant string.
// If this function returns false on the arguments to a function expecting a
@@ -6583,7 +6692,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
Sema::VariadicCallType CallType, bool InFunctionCall,
llvm::SmallBitVector &CheckedVarArgs,
UncoveredArgHandler &UncoveredArg,
- llvm::APSInt Offset) {
+ llvm::APSInt Offset,
+ bool IgnoreStringsWithoutSpecifiers = false) {
if (S.isConstantEvaluated())
return SLCT_NotALiteral;
tryAgain:
@@ -6634,17 +6744,17 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
Left = checkFormatStringExpr(S, C->getTrueExpr(), Args,
HasVAListArg, format_idx, firstDataArg,
Type, CallType, InFunctionCall,
- CheckedVarArgs, UncoveredArg, Offset);
+ CheckedVarArgs, UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
if (Left == SLCT_NotALiteral || !CheckRight) {
return Left;
}
}
- StringLiteralCheckType Right =
- checkFormatStringExpr(S, C->getFalseExpr(), Args,
- HasVAListArg, format_idx, firstDataArg,
- Type, CallType, InFunctionCall, CheckedVarArgs,
- UncoveredArg, Offset);
+ StringLiteralCheckType Right = checkFormatStringExpr(
+ S, C->getFalseExpr(), Args, HasVAListArg, format_idx, firstDataArg,
+ Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
return (CheckLeft && Left < Right) ? Left : Right;
}
@@ -6748,7 +6858,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex());
StringLiteralCheckType Result = checkFormatStringExpr(
S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
- CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset);
+ CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
if (IsFirst) {
CommonResult = Result;
IsFirst = false;
@@ -6766,7 +6877,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
HasVAListArg, format_idx,
firstDataArg, Type, CallType,
InFunctionCall, CheckedVarArgs,
- UncoveredArg, Offset);
+ UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
}
}
}
@@ -6775,12 +6887,28 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
}
case Stmt::ObjCMessageExprClass: {
const auto *ME = cast<ObjCMessageExpr>(E);
- if (const auto *ND = ME->getMethodDecl()) {
- if (const auto *FA = ND->getAttr<FormatArgAttr>()) {
+ if (const auto *MD = ME->getMethodDecl()) {
+ if (const auto *FA = MD->getAttr<FormatArgAttr>()) {
+ // As a special case heuristic, if we're using the method -[NSBundle
+ // localizedStringForKey:value:table:], ignore any key strings that lack
+ // format specifiers. The idea is that if the key doesn't have any
+ // format specifiers then its probably just a key to map to the
+ // localized strings. If it does have format specifiers though, then its
+ // likely that the text of the key is the format string in the
+ // programmer's language, and should be checked.
+ const ObjCInterfaceDecl *IFace;
+ if (MD->isInstanceMethod() && (IFace = MD->getClassInterface()) &&
+ IFace->getIdentifier()->isStr("NSBundle") &&
+ MD->getSelector().isKeywordSelector(
+ {"localizedStringForKey", "value", "table"})) {
+ IgnoreStringsWithoutSpecifiers = true;
+ }
+
const Expr *Arg = ME->getArg(FA->getFormatIdx().getASTIndex());
return checkFormatStringExpr(
S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
- CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset);
+ CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
}
}
@@ -6804,7 +6932,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
FormatStringLiteral FStr(StrE, Offset.sextOrTrunc(64).getSExtValue());
CheckFormatString(S, &FStr, E, Args, HasVAListArg, format_idx,
firstDataArg, Type, InFunctionCall, CallType,
- CheckedVarArgs, UncoveredArg);
+ CheckedVarArgs, UncoveredArg,
+ IgnoreStringsWithoutSpecifiers);
return SLCT_CheckedLiteral;
}
@@ -8072,9 +8201,23 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
ExprTy = TET->getUnderlyingExpr()->getType();
}
- const analyze_printf::ArgType::MatchKind Match =
- AT.matchesType(S.Context, ExprTy);
- bool Pedantic = Match == analyze_printf::ArgType::NoMatchPedantic;
+ // Diagnose attempts to print a boolean value as a character. Unlike other
+ // -Wformat diagnostics, this is fine from a type perspective, but it still
+ // doesn't make sense.
+ if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::cArg &&
+ E->isKnownToHaveBooleanValue()) {
+ const CharSourceRange &CSR =
+ getSpecifierRange(StartSpecifier, SpecifierLen);
+ SmallString<4> FSString;
+ llvm::raw_svector_ostream os(FSString);
+ FS.toString(os);
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_bool_as_character)
+ << FSString,
+ E->getExprLoc(), false, CSR);
+ return true;
+ }
+
+ analyze_printf::ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy);
if (Match == analyze_printf::ArgType::Match)
return true;
@@ -8093,9 +8236,14 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// function.
if (ICE->getType() == S.Context.IntTy ||
ICE->getType() == S.Context.UnsignedIntTy) {
- // All further checking is done on the subexpression.
- if (AT.matchesType(S.Context, ExprTy))
+ // All further checking is done on the subexpression
+ const analyze_printf::ArgType::MatchKind ImplicitMatch =
+ AT.matchesType(S.Context, ExprTy);
+ if (ImplicitMatch == analyze_printf::ArgType::Match)
return true;
+ if (ImplicitMatch == ArgType::NoMatchPedantic ||
+ ImplicitMatch == ArgType::NoMatchTypeConfusion)
+ Match = ImplicitMatch;
}
}
} else if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E)) {
@@ -8157,7 +8305,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
if ((CastTyName == "NSInteger" || CastTyName == "NSUInteger") &&
(AT.isSizeT() || AT.isPtrdiffT()) &&
AT.matchesType(S.Context, CastTy))
- Pedantic = true;
+ Match = ArgType::NoMatchPedantic;
IntendedTy = CastTy;
ShouldNotPrintDirectly = true;
}
@@ -8177,10 +8325,20 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen);
if (IntendedTy == ExprTy && !ShouldNotPrintDirectly) {
- unsigned Diag =
- Pedantic
- ? diag::warn_format_conversion_argument_type_mismatch_pedantic
- : diag::warn_format_conversion_argument_type_mismatch;
+ unsigned Diag;
+ switch (Match) {
+ case ArgType::Match: llvm_unreachable("expected non-matching");
+ case ArgType::NoMatchPedantic:
+ Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
+ break;
+ case ArgType::NoMatchTypeConfusion:
+ Diag = diag::warn_format_conversion_argument_type_mismatch_confusion;
+ break;
+ case ArgType::NoMatch:
+ Diag = diag::warn_format_conversion_argument_type_mismatch;
+ break;
+ }
+
// In this case, the specifier is wrong and should be changed to match
// the argument.
EmitFormatDiagnostic(S.PDiag(Diag)
@@ -8236,7 +8394,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
Name = TypedefTy->getDecl()->getName();
else
Name = CastTyName;
- unsigned Diag = Pedantic
+ unsigned Diag = Match == ArgType::NoMatchPedantic
? diag::warn_format_argument_needs_cast_pedantic
: diag::warn_format_argument_needs_cast;
EmitFormatDiagnostic(S.PDiag(Diag) << Name << IntendedTy << IsEnum
@@ -8263,10 +8421,19 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
switch (S.isValidVarArgType(ExprTy)) {
case Sema::VAK_Valid:
case Sema::VAK_ValidInCXX11: {
- unsigned Diag =
- Pedantic
- ? diag::warn_format_conversion_argument_type_mismatch_pedantic
- : diag::warn_format_conversion_argument_type_mismatch;
+ unsigned Diag;
+ switch (Match) {
+ case ArgType::Match: llvm_unreachable("expected non-matching");
+ case ArgType::NoMatchPedantic:
+ Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
+ break;
+ case ArgType::NoMatchTypeConfusion:
+ Diag = diag::warn_format_conversion_argument_type_mismatch_confusion;
+ break;
+ case ArgType::NoMatch:
+ Diag = diag::warn_format_conversion_argument_type_mismatch;
+ break;
+ }
EmitFormatDiagnostic(
S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy
@@ -8495,7 +8662,8 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr,
bool inFunctionCall,
Sema::VariadicCallType CallType,
llvm::SmallBitVector &CheckedVarArgs,
- UncoveredArgHandler &UncoveredArg) {
+ UncoveredArgHandler &UncoveredArg,
+ bool IgnoreStringsWithoutSpecifiers) {
// CHECK: is the format string a wide literal?
if (!FExpr->isAscii() && !FExpr->isUTF8()) {
CheckFormatHandler::EmitFormatDiagnostic(
@@ -8516,6 +8684,11 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr,
size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size());
const unsigned numDataArgs = Args.size() - firstDataArg;
+ if (IgnoreStringsWithoutSpecifiers &&
+ !analyze_format_string::parseFormatStringHasFormattingSpecifiers(
+ Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo()))
+ return;
+
// Emit a warning if the string literal is truncated and does not contain an
// embedded null character.
if (TypeSize <= StrRef.size() &&
@@ -10195,7 +10368,8 @@ static bool IsSameFloatAfterCast(const APValue &value,
IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
}
-static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC);
+static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC,
+ bool IsListInit = false);
static bool IsEnumConstOrFromMacro(Sema &S, Expr *E) {
// Suppress cases where we are comparing against an enum constant.
@@ -10627,7 +10801,7 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
return false;
if (BitfieldType->isEnumeralType()) {
- EnumDecl *BitfieldEnumDecl = BitfieldType->getAs<EnumType>()->getDecl();
+ EnumDecl *BitfieldEnumDecl = BitfieldType->castAs<EnumType>()->getDecl();
// If the underlying enum type was not explicitly specified as an unsigned
// type and the enum contain only positive values, MSVC++ will cause an
// inconsistency by storing this as a signed type.
@@ -10792,6 +10966,26 @@ static void DiagnoseImpCast(Sema &S, Expr *E, QualType T,
DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, pruneControlFlow);
}
+static bool isObjCSignedCharBool(Sema &S, QualType Ty) {
+ return Ty->isSpecificBuiltinType(BuiltinType::SChar) &&
+ S.getLangOpts().ObjC && S.NSAPIObj->isObjCBOOLType(Ty);
+}
+
+static void adornObjCBoolConversionDiagWithTernaryFixit(
+ Sema &S, Expr *SourceExpr, const Sema::SemaDiagnosticBuilder &Builder) {
+ Expr *Ignored = SourceExpr->IgnoreImplicit();
+ if (const auto *OVE = dyn_cast<OpaqueValueExpr>(Ignored))
+ Ignored = OVE->getSourceExpr();
+ bool NeedsParens = isa<AbstractConditionalOperator>(Ignored) ||
+ isa<BinaryOperator>(Ignored) ||
+ isa<CXXOperatorCallExpr>(Ignored);
+ SourceLocation EndLoc = S.getLocForEndOfToken(SourceExpr->getEndLoc());
+ if (NeedsParens)
+ Builder << FixItHint::CreateInsertion(SourceExpr->getBeginLoc(), "(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
+ Builder << FixItHint::CreateInsertion(EndLoc, " ? YES : NO");
+}
+
/// Diagnose an implicit cast from a floating point value to an integer value.
static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T,
SourceLocation CContext) {
@@ -10811,6 +11005,13 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T,
bool IsConstant =
E->EvaluateAsFloat(Value, S.Context, Expr::SE_AllowSideEffects);
if (!IsConstant) {
+ if (isObjCSignedCharBool(S, T)) {
+ return adornObjCBoolConversionDiagWithTernaryFixit(
+ S, E,
+ S.Diag(CContext, diag::warn_impcast_float_to_objc_signed_char_bool)
+ << E->getType());
+ }
+
return DiagnoseImpCast(S, E, T, CContext,
diag::warn_impcast_float_integer, PruneWarnings);
}
@@ -10822,6 +11023,23 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T,
llvm::APFloat::opStatus Result = Value.convertToInteger(
IntegerValue, llvm::APFloat::rmTowardZero, &isExact);
+ // FIXME: Force the precision of the source value down so we don't print
+ // digits which are usually useless (we don't really care here if we
+ // truncate a digit by accident in edge cases). Ideally, APFloat::toString
+ // would automatically print the shortest representation, but it's a bit
+ // tricky to implement.
+ SmallString<16> PrettySourceValue;
+ unsigned precision = llvm::APFloat::semanticsPrecision(Value.getSemantics());
+ precision = (precision * 59 + 195) / 196;
+ Value.toString(PrettySourceValue, precision);
+
+ if (isObjCSignedCharBool(S, T) && IntegerValue != 0 && IntegerValue != 1) {
+ return adornObjCBoolConversionDiagWithTernaryFixit(
+ S, E,
+ S.Diag(CContext, diag::warn_impcast_constant_value_to_objc_bool)
+ << PrettySourceValue);
+ }
+
if (Result == llvm::APFloat::opOK && isExact) {
if (IsLiteral) return;
return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer,
@@ -10865,16 +11083,6 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T,
DiagID = diag::warn_impcast_float_to_integer;
}
- // FIXME: Force the precision of the source value down so we don't print
- // digits which are usually useless (we don't really care here if we
- // truncate a digit by accident in edge cases). Ideally, APFloat::toString
- // would automatically print the shortest representation, but it's a bit
- // tricky to implement.
- SmallString<16> PrettySourceValue;
- unsigned precision = llvm::APFloat::semanticsPrecision(Value.getSemantics());
- precision = (precision * 59 + 195) / 196;
- Value.toString(PrettySourceValue, precision);
-
SmallString<16> PrettyTargetValue;
if (IsBool)
PrettyTargetValue = Value.isZero() ? "false" : "true";
@@ -11151,14 +11359,85 @@ static bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T,
return true;
}
-static bool isObjCSignedCharBool(Sema &S, QualType Ty) {
- return Ty->isSpecificBuiltinType(BuiltinType::SChar) &&
- S.getLangOpts().ObjC && S.NSAPIObj->isObjCBOOLType(Ty);
+static const IntegerLiteral *getIntegerLiteral(Expr *E) {
+ const auto *IL = dyn_cast<IntegerLiteral>(E);
+ if (!IL) {
+ if (auto *UO = dyn_cast<UnaryOperator>(E)) {
+ if (UO->getOpcode() == UO_Minus)
+ return dyn_cast<IntegerLiteral>(UO->getSubExpr());
+ }
+ }
+
+ return IL;
}
-static void
-CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
- bool *ICContext = nullptr) {
+static void CheckConditionalWithEnumTypes(Sema &S, SourceLocation Loc,
+ Expr *LHS, Expr *RHS) {
+ QualType LHSStrippedType = LHS->IgnoreParenImpCasts()->getType();
+ QualType RHSStrippedType = RHS->IgnoreParenImpCasts()->getType();
+
+ const auto *LHSEnumType = LHSStrippedType->getAs<EnumType>();
+ if (!LHSEnumType)
+ return;
+ const auto *RHSEnumType = RHSStrippedType->getAs<EnumType>();
+ if (!RHSEnumType)
+ return;
+
+ // Ignore anonymous enums.
+ if (!LHSEnumType->getDecl()->hasNameForLinkage())
+ return;
+ if (!RHSEnumType->getDecl()->hasNameForLinkage())
+ return;
+
+ if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType))
+ return;
+
+ S.Diag(Loc, diag::warn_conditional_mixed_enum_types)
+ << LHSStrippedType << RHSStrippedType << LHS->getSourceRange()
+ << RHS->getSourceRange();
+}
+
+static void DiagnoseIntInBoolContext(Sema &S, Expr *E) {
+ E = E->IgnoreParenImpCasts();
+ SourceLocation ExprLoc = E->getExprLoc();
+
+ if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
+ BinaryOperator::Opcode Opc = BO->getOpcode();
+ Expr::EvalResult Result;
+ // Do not diagnose unsigned shifts.
+ if (Opc == BO_Shl) {
+ const auto *LHS = getIntegerLiteral(BO->getLHS());
+ const auto *RHS = getIntegerLiteral(BO->getRHS());
+ if (LHS && LHS->getValue() == 0)
+ S.Diag(ExprLoc, diag::warn_left_shift_always) << 0;
+ else if (!E->isValueDependent() && LHS && RHS &&
+ RHS->getValue().isNonNegative() &&
+ E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects))
+ S.Diag(ExprLoc, diag::warn_left_shift_always)
+ << (Result.Val.getInt() != 0);
+ else if (E->getType()->isSignedIntegerType())
+ S.Diag(ExprLoc, diag::warn_left_shift_in_bool_context) << E;
+ }
+ }
+
+ if (const auto *CO = dyn_cast<ConditionalOperator>(E)) {
+ const auto *LHS = getIntegerLiteral(CO->getTrueExpr());
+ const auto *RHS = getIntegerLiteral(CO->getFalseExpr());
+ if (!LHS || !RHS)
+ return;
+ if ((LHS->getValue() == 0 || LHS->getValue() == 1) &&
+ (RHS->getValue() == 0 || RHS->getValue() == 1))
+ // Do not diagnose common idioms.
+ return;
+ if (LHS->getValue() != 0 && RHS->getValue() != 0)
+ S.Diag(ExprLoc, diag::warn_integer_constants_in_conditional_always_true);
+ }
+}
+
+static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
+ SourceLocation CC,
+ bool *ICContext = nullptr,
+ bool IsListInit = false) {
if (E->isTypeDependent() || E->isValueDependent()) return;
const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr();
@@ -11205,19 +11484,13 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
if (isObjCSignedCharBool(S, T) && Source->isIntegralType(S.Context)) {
Expr::EvalResult Result;
if (E->EvaluateAsInt(Result, S.getASTContext(),
- Expr::SE_AllowSideEffects) &&
- Result.Val.getInt() != 1 && Result.Val.getInt() != 0) {
- auto Builder = S.Diag(CC, diag::warn_impcast_constant_int_to_objc_bool)
- << Result.Val.getInt().toString(10);
- Expr *Ignored = E->IgnoreImplicit();
- bool NeedsParens = isa<AbstractConditionalOperator>(Ignored) ||
- isa<BinaryOperator>(Ignored) ||
- isa<CXXOperatorCallExpr>(Ignored);
- SourceLocation EndLoc = S.getLocForEndOfToken(E->getEndLoc());
- if (NeedsParens)
- Builder << FixItHint::CreateInsertion(E->getBeginLoc(), "(")
- << FixItHint::CreateInsertion(EndLoc, ")");
- Builder << FixItHint::CreateInsertion(EndLoc, " ? YES : NO");
+ Expr::SE_AllowSideEffects)) {
+ if (Result.Val.getInt() != 1 && Result.Val.getInt() != 0) {
+ adornObjCBoolConversionDiagWithTernaryFixit(
+ S, E,
+ S.Diag(CC, diag::warn_impcast_constant_value_to_objc_bool)
+ << Result.Val.getInt().toString(10));
+ }
return;
}
}
@@ -11400,10 +11673,61 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
}
}
+ // If we are casting an integer type to a floating point type without
+ // initialization-list syntax, we might lose accuracy if the floating
+ // point type has a narrower significand than the integer type.
+ if (SourceBT && TargetBT && SourceBT->isIntegerType() &&
+ TargetBT->isFloatingType() && !IsListInit) {
+ // Determine the number of precision bits in the source integer type.
+ IntRange SourceRange = GetExprRange(S.Context, E, S.isConstantEvaluated());
+ unsigned int SourcePrecision = SourceRange.Width;
+
+ // Determine the number of precision bits in the
+ // target floating point type.
+ unsigned int TargetPrecision = llvm::APFloatBase::semanticsPrecision(
+ S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)));
+
+ if (SourcePrecision > 0 && TargetPrecision > 0 &&
+ SourcePrecision > TargetPrecision) {
+
+ llvm::APSInt SourceInt;
+ if (E->isIntegerConstantExpr(SourceInt, S.Context)) {
+ // If the source integer is a constant, convert it to the target
+ // floating point type. Issue a warning if the value changes
+ // during the whole conversion.
+ llvm::APFloat TargetFloatValue(
+ S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)));
+ llvm::APFloat::opStatus ConversionStatus =
+ TargetFloatValue.convertFromAPInt(
+ SourceInt, SourceBT->isSignedInteger(),
+ llvm::APFloat::rmNearestTiesToEven);
+
+ if (ConversionStatus != llvm::APFloat::opOK) {
+ std::string PrettySourceValue = SourceInt.toString(10);
+ SmallString<32> PrettyTargetValue;
+ TargetFloatValue.toString(PrettyTargetValue, TargetPrecision);
+
+ S.DiagRuntimeBehavior(
+ E->getExprLoc(), E,
+ S.PDiag(diag::warn_impcast_integer_float_precision_constant)
+ << PrettySourceValue << PrettyTargetValue << E->getType() << T
+ << E->getSourceRange() << clang::SourceRange(CC));
+ }
+ } else {
+ // Otherwise, the implicit conversion may lose precision.
+ DiagnoseImpCast(S, E, T, CC,
+ diag::warn_impcast_integer_float_precision);
+ }
+ }
+ }
+
DiagnoseNullConversion(S, E, T, CC);
S.DiscardMisalignedMemberAddress(Target, E);
+ if (Target->isBooleanType())
+ DiagnoseIntInBoolContext(S, E);
+
if (!Source->isIntegerType() || !Target->isIntegerType())
return;
@@ -11412,6 +11736,14 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
if (Target->isSpecificBuiltinType(BuiltinType::Bool))
return;
+ if (isObjCSignedCharBool(S, T) && !Source->isCharType() &&
+ !E->isKnownToHaveBooleanValue()) {
+ return adornObjCBoolConversionDiagWithTernaryFixit(
+ S, E,
+ S.Diag(CC, diag::warn_impcast_int_to_objc_signed_char_bool)
+ << E->getType());
+ }
+
IntRange SourceRange = GetExprRange(S.Context, E, S.isConstantEvaluated());
IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target);
@@ -11556,6 +11888,11 @@ static void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
bool Suspicious = false;
CheckConditionalOperand(S, E->getTrueExpr(), T, CC, Suspicious);
CheckConditionalOperand(S, E->getFalseExpr(), T, CC, Suspicious);
+ CheckConditionalWithEnumTypes(S, E->getBeginLoc(), E->getTrueExpr(),
+ E->getFalseExpr());
+
+ if (T->isBooleanType())
+ DiagnoseIntInBoolContext(S, E);
// If -Wconversion would have warned about either of the candidates
// for a signedness conversion to the context type...
@@ -11590,14 +11927,27 @@ static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) {
/// AnalyzeImplicitConversions - Find and report any interesting
/// implicit conversions in the given expression. There are a couple
/// of competing diagnostics here, -Wconversion and -Wsign-compare.
-static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE,
- SourceLocation CC) {
+static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC,
+ bool IsListInit/*= false*/) {
QualType T = OrigE->getType();
Expr *E = OrigE->IgnoreParenImpCasts();
+ // Propagate whether we are in a C++ list initialization expression.
+ // If so, we do not issue warnings for implicit int-float conversion
+ // precision loss, because C++11 narrowing already handles it.
+ IsListInit =
+ IsListInit || (isa<InitListExpr>(OrigE) && S.getLangOpts().CPlusPlus);
+
if (E->isTypeDependent() || E->isValueDependent())
return;
+ if (const auto *UO = dyn_cast<UnaryOperator>(E))
+ if (UO->getOpcode() == UO_Not &&
+ UO->getSubExpr()->isKnownToHaveBooleanValue())
+ S.Diag(UO->getBeginLoc(), diag::warn_bitwise_negation_bool)
+ << OrigE->getSourceRange() << T->isBooleanType()
+ << FixItHint::CreateReplacement(UO->getBeginLoc(), "!");
+
// For conditional operators, we analyze the arguments as if they
// were being fed directly into the output.
if (isa<ConditionalOperator>(E)) {
@@ -11614,7 +11964,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE,
// The non-canonical typecheck is just an optimization;
// CheckImplicitConversion will filter out dead implicit conversions.
if (E->getType() != T)
- CheckImplicitConversion(S, E, T, CC);
+ CheckImplicitConversion(S, E, T, CC, nullptr, IsListInit);
// Now continue drilling into this expression.
@@ -11624,7 +11974,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE,
// FIXME: Use a more uniform representation for this.
for (auto *SE : POE->semantics())
if (auto *OVE = dyn_cast<OpaqueValueExpr>(SE))
- AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC);
+ AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC, IsListInit);
}
// Skip past explicit casts.
@@ -11632,7 +11982,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE,
E = CE->getSubExpr()->IgnoreParenImpCasts();
if (!CE->getType()->isVoidType() && E->getType()->isAtomicType())
S.Diag(E->getBeginLoc(), diag::warn_atomic_implicit_seq_cst);
- return AnalyzeImplicitConversions(S, E, CC);
+ return AnalyzeImplicitConversions(S, E, CC, IsListInit);
}
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
@@ -11671,7 +12021,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE,
// Ignore checking string literals that are in logical and operators.
// This is a common pattern for asserts.
continue;
- AnalyzeImplicitConversions(S, ChildExpr, CC);
+ AnalyzeImplicitConversions(S, ChildExpr, CC, IsListInit);
}
if (BO && BO->isLogicalOp()) {
@@ -12907,7 +13257,7 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
if (ND)
DiagRuntimeBehavior(ND->getBeginLoc(), BaseExpr,
- PDiag(diag::note_array_index_out_of_bounds)
+ PDiag(diag::note_array_declared_here)
<< ND->getDeclName());
}
@@ -14229,7 +14579,7 @@ void Sema::RefersToMemberWithReducedAlignment(
QualType BaseType = ME->getBase()->getType();
if (ME->isArrow())
BaseType = BaseType->getPointeeType();
- RecordDecl *RD = BaseType->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = BaseType->castAs<RecordType>()->getDecl();
if (RD->isInvalidDecl())
return;
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index e4bbee86e350..f24c3b234ff2 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -1185,6 +1185,9 @@ static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate,
const CXXMethodDecl &Incumbent,
const Qualifiers &ObjectQuals,
ExprValueKind ObjectKind) {
+ // Base/derived shadowing is handled elsewhere.
+ if (Candidate.getDeclContext() != Incumbent.getDeclContext())
+ return OverloadCompare::BothViable;
if (Candidate.isVariadic() != Incumbent.isVariadic() ||
Candidate.getNumParams() != Incumbent.getNumParams() ||
Candidate.getMinRequiredArguments() !=
diff --git a/lib/Sema/SemaConcept.cpp b/lib/Sema/SemaConcept.cpp
new file mode 100644
index 000000000000..848ccf543445
--- /dev/null
+++ b/lib/Sema/SemaConcept.cpp
@@ -0,0 +1,125 @@
+//===-- SemaConcept.cpp - Semantic Analysis for Constraints and Concepts --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for C++ constraints and concepts.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Sema/TemplateDeduction.h"
+#include "clang/Sema/Template.h"
+#include "clang/AST/ExprCXX.h"
+using namespace clang;
+using namespace sema;
+
+bool Sema::CheckConstraintExpression(Expr *ConstraintExpression) {
+ // C++2a [temp.constr.atomic]p1
+ // ..E shall be a constant expression of type bool.
+
+ ConstraintExpression = ConstraintExpression->IgnoreParenImpCasts();
+
+ if (auto *BinOp = dyn_cast<BinaryOperator>(ConstraintExpression)) {
+ if (BinOp->getOpcode() == BO_LAnd || BinOp->getOpcode() == BO_LOr)
+ return CheckConstraintExpression(BinOp->getLHS()) &&
+ CheckConstraintExpression(BinOp->getRHS());
+ } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpression))
+ return CheckConstraintExpression(C->getSubExpr());
+
+ // An atomic constraint!
+ if (ConstraintExpression->isTypeDependent())
+ return true;
+
+ QualType Type = ConstraintExpression->getType();
+ if (!Context.hasSameUnqualifiedType(Type, Context.BoolTy)) {
+ Diag(ConstraintExpression->getExprLoc(),
+ diag::err_non_bool_atomic_constraint) << Type
+ << ConstraintExpression->getSourceRange();
+ return false;
+ }
+ return true;
+}
+
+bool
+Sema::CalculateConstraintSatisfaction(ConceptDecl *NamedConcept,
+ MultiLevelTemplateArgumentList &MLTAL,
+ Expr *ConstraintExpr,
+ bool &IsSatisfied) {
+ ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
+
+ if (auto *BO = dyn_cast<BinaryOperator>(ConstraintExpr)) {
+ if (BO->getOpcode() == BO_LAnd) {
+ if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(),
+ IsSatisfied))
+ return true;
+ if (!IsSatisfied)
+ return false;
+ return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(),
+ IsSatisfied);
+ } else if (BO->getOpcode() == BO_LOr) {
+ if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(),
+ IsSatisfied))
+ return true;
+ if (IsSatisfied)
+ return false;
+ return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(),
+ IsSatisfied);
+ }
+ }
+ else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr))
+ return CalculateConstraintSatisfaction(NamedConcept, MLTAL, C->getSubExpr(),
+ IsSatisfied);
+
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ *this, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+
+ // Atomic constraint - substitute arguments and check satisfaction.
+ ExprResult E;
+ {
+ TemplateDeductionInfo Info(ConstraintExpr->getBeginLoc());
+ InstantiatingTemplate Inst(*this, ConstraintExpr->getBeginLoc(),
+ InstantiatingTemplate::ConstraintSubstitution{},
+ NamedConcept, Info,
+ ConstraintExpr->getSourceRange());
+ if (Inst.isInvalid())
+ return true;
+ // We do not want error diagnostics escaping here.
+ Sema::SFINAETrap Trap(*this);
+
+ E = SubstExpr(ConstraintExpr, MLTAL);
+ if (E.isInvalid() || Trap.hasErrorOccurred()) {
+ // C++2a [temp.constr.atomic]p1
+ // ...If substitution results in an invalid type or expression, the
+ // constraint is not satisfied.
+ IsSatisfied = false;
+ return false;
+ }
+ }
+
+ if (!CheckConstraintExpression(E.get()))
+ return true;
+
+ SmallVector<PartialDiagnosticAt, 2> EvaluationDiags;
+ Expr::EvalResult EvalResult;
+ EvalResult.Diag = &EvaluationDiags;
+ if (!E.get()->EvaluateAsRValue(EvalResult, Context)) {
+ // C++2a [temp.constr.atomic]p1
+ // ...E shall be a constant expression of type bool.
+ Diag(E.get()->getBeginLoc(),
+ diag::err_non_constant_constraint_expression)
+ << E.get()->getSourceRange();
+ for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
+ Diag(PDiag.first, PDiag.second);
+ return true;
+ }
+
+ IsSatisfied = EvalResult.Val.getInt().getBoolValue();
+
+ return false;
+} \ No newline at end of file
diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp
index f0347af6a1bb..fd2fd35921ce 100644
--- a/lib/Sema/SemaCoroutine.cpp
+++ b/lib/Sema/SemaCoroutine.cpp
@@ -83,7 +83,7 @@ static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD,
// ref-qualifier or with the & ref-qualifier
// -- "rvalue reference to cv X" for functions declared with the &&
// ref-qualifier
- QualType T = MD->getThisType()->getAs<PointerType>()->getPointeeType();
+ QualType T = MD->getThisType()->castAs<PointerType>()->getPointeeType();
T = FnType->getRefQualifier() == RQ_RValue
? S.Context.getRValueReferenceType(T)
: S.Context.getLValueReferenceType(T, /*SpelledAsLValue*/ true);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index a6c52b7d4b2b..62ec83967bff 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -107,7 +107,7 @@ class TypeNameValidatorCCC final : public CorrectionCandidateCallback {
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<TypeNameValidatorCCC>(*this);
+ return std::make_unique<TypeNameValidatorCCC>(*this);
}
private:
@@ -845,18 +845,18 @@ static ParsedType buildNestedType(Sema &S, CXXScopeSpec &SS,
return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
}
-Sema::NameClassification
-Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name,
- SourceLocation NameLoc, const Token &NextToken,
- bool IsAddressOfOperand, CorrectionCandidateCallback *CCC) {
+Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
+ IdentifierInfo *&Name,
+ SourceLocation NameLoc,
+ const Token &NextToken,
+ CorrectionCandidateCallback *CCC) {
DeclarationNameInfo NameInfo(Name, NameLoc);
ObjCMethodDecl *CurMethod = getCurMethodDecl();
- if (NextToken.is(tok::coloncolon)) {
- NestedNameSpecInfo IdInfo(Name, NameLoc, NextToken.getLocation());
- BuildCXXNestedNameSpecifier(S, IdInfo, false, SS, nullptr, false);
- } else if (getLangOpts().CPlusPlus && SS.isSet() &&
- isCurrentClassName(*Name, S, &SS)) {
+ assert(NextToken.isNot(tok::coloncolon) &&
+ "parse nested name specifiers before calling ClassifyName");
+ if (getLangOpts().CPlusPlus && SS.isSet() &&
+ isCurrentClassName(*Name, S, &SS)) {
// Per [class.qual]p2, this names the constructors of SS, not the
// injected-class-name. We don't have a classification for that.
// There's not much point caching this result, since the parser
@@ -880,9 +880,15 @@ Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name,
// FIXME: This lookup really, really needs to be folded in to the normal
// unqualified lookup mechanism.
if (!SS.isSet() && CurMethod && !isResultTypeOrTemplate(Result, NextToken)) {
- ExprResult E = LookupInObjCMethod(Result, S, Name, true);
- if (E.get() || E.isInvalid())
- return E;
+ DeclResult Ivar = LookupIvarInObjCMethod(Result, S, Name);
+ if (Ivar.isInvalid())
+ return NameClassification::Error();
+ if (Ivar.isUsable())
+ return NameClassification::NonType(cast<NamedDecl>(Ivar.get()));
+
+ // We defer builtin creation until after ivar lookup inside ObjC methods.
+ if (Result.empty())
+ LookupBuiltin(Result);
}
bool SecondTry = false;
@@ -897,7 +903,7 @@ Corrected:
// In C++, this is an ADL-only call.
// FIXME: Reference?
if (getLangOpts().CPlusPlus)
- return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true);
+ return NameClassification::UndeclaredNonType();
// C90 6.3.2.2:
// If the expression that precedes the parenthesized argument list in a
@@ -911,11 +917,8 @@ Corrected:
// appeared.
//
// We also allow this in C99 as an extension.
- if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S)) {
- Result.addDecl(D);
- Result.resolveKind();
- return BuildDeclarationNameExpr(SS, Result, /*ADL=*/false);
- }
+ if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S))
+ return NameClassification::NonType(D);
}
if (getLangOpts().CPlusPlus2a && !SS.isSet() && NextToken.is(tok::less)) {
@@ -990,9 +993,12 @@ Corrected:
// reference the ivar.
// FIXME: This is a gross hack.
if (ObjCIvarDecl *Ivar = Result.getAsSingle<ObjCIvarDecl>()) {
- Result.clear();
- ExprResult E(LookupInObjCMethod(Result, S, Ivar->getIdentifier()));
- return E;
+ DeclResult R =
+ LookupIvarInObjCMethod(Result, S, Ivar->getIdentifier());
+ if (R.isInvalid())
+ return NameClassification::Error();
+ if (R.isUsable())
+ return NameClassification::NonType(Ivar);
}
goto Corrected;
@@ -1018,9 +1024,7 @@ Corrected:
// perform some heroics to see if we actually have a
// template-argument-list, which would indicate a missing 'template'
// keyword here.
- return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(),
- NameInfo, IsAddressOfOperand,
- /*TemplateArgs=*/nullptr);
+ return NameClassification::DependentNonType();
}
case LookupResult::Found:
@@ -1167,9 +1171,57 @@ Corrected:
return ParsedType::make(T);
}
+ // FIXME: This is context-dependent. We need to defer building the member
+ // expression until the classification is consumed.
if (FirstDecl->isCXXClassMember())
- return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result,
- nullptr, S);
+ return NameClassification::ContextIndependentExpr(
+ BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, nullptr,
+ S));
+
+ // If we already know which single declaration is referenced, just annotate
+ // that declaration directly.
+ bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren));
+ if (Result.isSingleResult() && !ADL)
+ return NameClassification::NonType(Result.getRepresentativeDecl());
+
+ // Build an UnresolvedLookupExpr. Note that this doesn't depend on the
+ // context in which we performed classification, so it's safe to do now.
+ return NameClassification::ContextIndependentExpr(
+ BuildDeclarationNameExpr(SS, Result, ADL));
+}
+
+ExprResult
+Sema::ActOnNameClassifiedAsUndeclaredNonType(IdentifierInfo *Name,
+ SourceLocation NameLoc) {
+ assert(getLangOpts().CPlusPlus && "ADL-only call in C?");
+ CXXScopeSpec SS;
+ LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
+ return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true);
+}
+
+ExprResult
+Sema::ActOnNameClassifiedAsDependentNonType(const CXXScopeSpec &SS,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ bool IsAddressOfOperand) {
+ DeclarationNameInfo NameInfo(Name, NameLoc);
+ return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(),
+ NameInfo, IsAddressOfOperand,
+ /*TemplateArgs=*/nullptr);
+}
+
+ExprResult Sema::ActOnNameClassifiedAsNonType(Scope *S, const CXXScopeSpec &SS,
+ NamedDecl *Found,
+ SourceLocation NameLoc,
+ const Token &NextToken) {
+ if (getCurMethodDecl() && SS.isEmpty())
+ if (auto *Ivar = dyn_cast<ObjCIvarDecl>(Found->getUnderlyingDecl()))
+ return BuildIvarRefExpr(S, NameLoc, Ivar);
+
+ // Reconstruct the lookup result.
+ LookupResult Result(*this, Found->getDeclName(), NameLoc, LookupOrdinaryName);
+ Result.addDecl(Found);
+ Result.resolveKind();
bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren));
return BuildDeclarationNameExpr(SS, Result, ADL);
@@ -1984,10 +2036,27 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
ASTContext::GetBuiltinTypeError Error;
QualType R = Context.GetBuiltinType(ID, Error);
if (Error) {
- if (ForRedeclaration)
- Diag(Loc, diag::warn_implicit_decl_requires_sysheader)
- << getHeaderName(Context.BuiltinInfo, ID, Error)
+ if (!ForRedeclaration)
+ return nullptr;
+
+ // If we have a builtin without an associated type we should not emit a
+ // warning when we were not able to find a type for it.
+ if (Error == ASTContext::GE_Missing_type)
+ return nullptr;
+
+ // If we could not find a type for setjmp it is because the jmp_buf type was
+ // not defined prior to the setjmp declaration.
+ if (Error == ASTContext::GE_Missing_setjmp) {
+ Diag(Loc, diag::warn_implicit_decl_no_jmp_buf)
<< Context.BuiltinInfo.getName(ID);
+ return nullptr;
+ }
+
+ // Generally, we emit a warning that the declaration requires the
+ // appropriate header.
+ Diag(Loc, diag::warn_implicit_decl_requires_sysheader)
+ << getHeaderName(Context.BuiltinInfo, ID, Error)
+ << Context.BuiltinInfo.getName(ID);
return nullptr;
}
@@ -2155,7 +2224,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New,
if (!T->isPointerType())
break;
if (!T->isVoidPointerType()) {
- QualType PT = T->getAs<PointerType>()->getPointeeType();
+ QualType PT = T->castAs<PointerType>()->getPointeeType();
if (!PT->isStructureType())
break;
}
@@ -2457,43 +2526,33 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
// previous decl", for example if the attribute needs to be consistent
// between redeclarations, you need to call a custom merge function here.
InheritableAttr *NewAttr = nullptr;
- unsigned AttrSpellingListIndex = Attr->getSpellingListIndex();
if (const auto *AA = dyn_cast<AvailabilityAttr>(Attr))
NewAttr = S.mergeAvailabilityAttr(
- D, AA->getRange(), AA->getPlatform(), AA->isImplicit(),
- AA->getIntroduced(), AA->getDeprecated(), AA->getObsoleted(),
- AA->getUnavailable(), AA->getMessage(), AA->getStrict(),
- AA->getReplacement(), AMK, AA->getPriority(), AttrSpellingListIndex);
+ D, *AA, AA->getPlatform(), AA->isImplicit(), AA->getIntroduced(),
+ AA->getDeprecated(), AA->getObsoleted(), AA->getUnavailable(),
+ AA->getMessage(), AA->getStrict(), AA->getReplacement(), AMK,
+ AA->getPriority());
else if (const auto *VA = dyn_cast<VisibilityAttr>(Attr))
- NewAttr = S.mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
- AttrSpellingListIndex);
+ NewAttr = S.mergeVisibilityAttr(D, *VA, VA->getVisibility());
else if (const auto *VA = dyn_cast<TypeVisibilityAttr>(Attr))
- NewAttr = S.mergeTypeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
- AttrSpellingListIndex);
+ NewAttr = S.mergeTypeVisibilityAttr(D, *VA, VA->getVisibility());
else if (const auto *ImportA = dyn_cast<DLLImportAttr>(Attr))
- NewAttr = S.mergeDLLImportAttr(D, ImportA->getRange(),
- AttrSpellingListIndex);
+ NewAttr = S.mergeDLLImportAttr(D, *ImportA);
else if (const auto *ExportA = dyn_cast<DLLExportAttr>(Attr))
- NewAttr = S.mergeDLLExportAttr(D, ExportA->getRange(),
- AttrSpellingListIndex);
+ NewAttr = S.mergeDLLExportAttr(D, *ExportA);
else if (const auto *FA = dyn_cast<FormatAttr>(Attr))
- NewAttr = S.mergeFormatAttr(D, FA->getRange(), FA->getType(),
- FA->getFormatIdx(), FA->getFirstArg(),
- AttrSpellingListIndex);
+ NewAttr = S.mergeFormatAttr(D, *FA, FA->getType(), FA->getFormatIdx(),
+ FA->getFirstArg());
else if (const auto *SA = dyn_cast<SectionAttr>(Attr))
- NewAttr = S.mergeSectionAttr(D, SA->getRange(), SA->getName(),
- AttrSpellingListIndex);
+ NewAttr = S.mergeSectionAttr(D, *SA, SA->getName());
else if (const auto *CSA = dyn_cast<CodeSegAttr>(Attr))
- NewAttr = S.mergeCodeSegAttr(D, CSA->getRange(), CSA->getName(),
- AttrSpellingListIndex);
+ NewAttr = S.mergeCodeSegAttr(D, *CSA, CSA->getName());
else if (const auto *IA = dyn_cast<MSInheritanceAttr>(Attr))
- NewAttr = S.mergeMSInheritanceAttr(D, IA->getRange(), IA->getBestCase(),
- AttrSpellingListIndex,
+ NewAttr = S.mergeMSInheritanceAttr(D, *IA, IA->getBestCase(),
IA->getSemanticSpelling());
else if (const auto *AA = dyn_cast<AlwaysInlineAttr>(Attr))
- NewAttr = S.mergeAlwaysInlineAttr(D, AA->getRange(),
- &S.Context.Idents.get(AA->getSpelling()),
- AttrSpellingListIndex);
+ NewAttr = S.mergeAlwaysInlineAttr(D, *AA,
+ &S.Context.Idents.get(AA->getSpelling()));
else if (S.getLangOpts().CUDA && isa<FunctionDecl>(D) &&
(isa<CUDAHostAttr>(Attr) || isa<CUDADeviceAttr>(Attr) ||
isa<CUDAGlobalAttr>(Attr))) {
@@ -2501,9 +2560,9 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
// overloading purposes and must not be merged.
return false;
} else if (const auto *MA = dyn_cast<MinSizeAttr>(Attr))
- NewAttr = S.mergeMinSizeAttr(D, MA->getRange(), AttrSpellingListIndex);
+ NewAttr = S.mergeMinSizeAttr(D, *MA);
else if (const auto *OA = dyn_cast<OptimizeNoneAttr>(Attr))
- NewAttr = S.mergeOptimizeNoneAttr(D, OA->getRange(), AttrSpellingListIndex);
+ NewAttr = S.mergeOptimizeNoneAttr(D, *OA);
else if (const auto *InternalLinkageA = dyn_cast<InternalLinkageAttr>(Attr))
NewAttr = S.mergeInternalLinkageAttr(D, *InternalLinkageA);
else if (const auto *CommonA = dyn_cast<CommonAttr>(Attr))
@@ -2517,8 +2576,7 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
AMK == Sema::AMK_ProtocolImplementation))
NewAttr = nullptr;
else if (const auto *UA = dyn_cast<UuidAttr>(Attr))
- NewAttr = S.mergeUuidAttr(D, UA->getRange(), AttrSpellingListIndex,
- UA->getGuid());
+ NewAttr = S.mergeUuidAttr(D, *UA, UA->getGuid());
else if (const auto *SLHA = dyn_cast<SpeculativeLoadHardeningAttr>(Attr))
NewAttr = S.mergeSpeculativeLoadHardeningAttr(D, *SLHA);
else if (const auto *SLHA = dyn_cast<NoSpeculativeLoadHardeningAttr>(Attr))
@@ -2635,6 +2693,15 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
--E;
continue;
}
+ } else if (isa<SelectAnyAttr>(NewAttribute) &&
+ cast<VarDecl>(New)->isInline() &&
+ !cast<VarDecl>(New)->isInlineSpecified()) {
+ // Don't warn about applying selectany to implicitly inline variables.
+ // Older compilers and language modes would require the use of selectany
+ // to make such variables inline, and it would have no effect if we
+ // honored it.
+ ++I;
+ continue;
}
S.Diag(NewAttribute->getLocation(),
@@ -2645,6 +2712,60 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
}
}
+static void diagnoseMissingConstinit(Sema &S, const VarDecl *InitDecl,
+ const ConstInitAttr *CIAttr,
+ bool AttrBeforeInit) {
+ SourceLocation InsertLoc = InitDecl->getInnerLocStart();
+
+ // Figure out a good way to write this specifier on the old declaration.
+ // FIXME: We should just use the spelling of CIAttr, but we don't preserve
+ // enough of the attribute list spelling information to extract that without
+ // heroics.
+ std::string SuitableSpelling;
+ if (S.getLangOpts().CPlusPlus2a)
+ SuitableSpelling =
+ S.PP.getLastMacroWithSpelling(InsertLoc, {tok::kw_constinit});
+ if (SuitableSpelling.empty() && S.getLangOpts().CPlusPlus11)
+ SuitableSpelling = S.PP.getLastMacroWithSpelling(
+ InsertLoc,
+ {tok::l_square, tok::l_square, S.PP.getIdentifierInfo("clang"),
+ tok::coloncolon,
+ S.PP.getIdentifierInfo("require_constant_initialization"),
+ tok::r_square, tok::r_square});
+ if (SuitableSpelling.empty())
+ SuitableSpelling = S.PP.getLastMacroWithSpelling(
+ InsertLoc,
+ {tok::kw___attribute, tok::l_paren, tok::r_paren,
+ S.PP.getIdentifierInfo("require_constant_initialization"),
+ tok::r_paren, tok::r_paren});
+ if (SuitableSpelling.empty() && S.getLangOpts().CPlusPlus2a)
+ SuitableSpelling = "constinit";
+ if (SuitableSpelling.empty() && S.getLangOpts().CPlusPlus11)
+ SuitableSpelling = "[[clang::require_constant_initialization]]";
+ if (SuitableSpelling.empty())
+ SuitableSpelling = "__attribute__((require_constant_initialization))";
+ SuitableSpelling += " ";
+
+ if (AttrBeforeInit) {
+ // extern constinit int a;
+ // int a = 0; // error (missing 'constinit'), accepted as extension
+ assert(CIAttr->isConstinit() && "should not diagnose this for attribute");
+ S.Diag(InitDecl->getLocation(), diag::ext_constinit_missing)
+ << InitDecl << FixItHint::CreateInsertion(InsertLoc, SuitableSpelling);
+ S.Diag(CIAttr->getLocation(), diag::note_constinit_specified_here);
+ } else {
+ // int a = 0;
+ // constinit extern int a; // error (missing 'constinit')
+ S.Diag(CIAttr->getLocation(),
+ CIAttr->isConstinit() ? diag::err_constinit_added_too_late
+ : diag::warn_require_const_init_added_too_late)
+ << FixItHint::CreateRemoval(SourceRange(CIAttr->getLocation()));
+ S.Diag(InitDecl->getLocation(), diag::note_constinit_missing_here)
+ << CIAttr->isConstinit()
+ << FixItHint::CreateInsertion(InsertLoc, SuitableSpelling);
+ }
+}
+
/// mergeDeclAttributes - Copy attributes from the Old decl to the New one.
void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
AvailabilityMergeKind AMK) {
@@ -2657,12 +2778,47 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
if (!Old->hasAttrs() && !New->hasAttrs())
return;
+ // [dcl.constinit]p1:
+ // If the [constinit] specifier is applied to any declaration of a
+ // variable, it shall be applied to the initializing declaration.
+ const auto *OldConstInit = Old->getAttr<ConstInitAttr>();
+ const auto *NewConstInit = New->getAttr<ConstInitAttr>();
+ if (bool(OldConstInit) != bool(NewConstInit)) {
+ const auto *OldVD = cast<VarDecl>(Old);
+ auto *NewVD = cast<VarDecl>(New);
+
+ // Find the initializing declaration. Note that we might not have linked
+ // the new declaration into the redeclaration chain yet.
+ const VarDecl *InitDecl = OldVD->getInitializingDeclaration();
+ if (!InitDecl &&
+ (NewVD->hasInit() || NewVD->isThisDeclarationADefinition()))
+ InitDecl = NewVD;
+
+ if (InitDecl == NewVD) {
+ // This is the initializing declaration. If it would inherit 'constinit',
+ // that's ill-formed. (Note that we do not apply this to the attribute
+ // form).
+ if (OldConstInit && OldConstInit->isConstinit())
+ diagnoseMissingConstinit(*this, NewVD, OldConstInit,
+ /*AttrBeforeInit=*/true);
+ } else if (NewConstInit) {
+ // This is the first time we've been told that this declaration should
+ // have a constant initializer. If we already saw the initializing
+ // declaration, this is too late.
+ if (InitDecl && InitDecl != NewVD) {
+ diagnoseMissingConstinit(*this, InitDecl, NewConstInit,
+ /*AttrBeforeInit=*/false);
+ NewVD->dropAttr<ConstInitAttr>();
+ }
+ }
+ }
+
// Attributes declared post-definition are currently ignored.
checkNewAttributesAfterDef(*this, New, Old);
if (AsmLabelAttr *NewA = New->getAttr<AsmLabelAttr>()) {
if (AsmLabelAttr *OldA = Old->getAttr<AsmLabelAttr>()) {
- if (OldA->getLabel() != NewA->getLabel()) {
+ if (!OldA->isEquivalent(NewA)) {
// This redeclaration changes __asm__ label.
Diag(New->getLocation(), diag::err_different_asm_label);
Diag(OldA->getLocation(), diag::note_previous_declaration);
@@ -3458,7 +3614,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
}
}
- if (OldQTypeForComparison == NewQType)
+ // If the function types are compatible, merge the declarations. Ignore the
+ // exception specifier because it was already checked above in
+ // CheckEquivalentExceptionSpec, and we don't want follow-on diagnostics
+ // about incompatible types under -fms-compatibility.
+ if (Context.hasSameFunctionTypeIgnoringExceptionSpec(OldQTypeForComparison,
+ NewQType))
return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld);
// If the types are imprecise (due to dependent constructs in friends or
@@ -4090,11 +4251,11 @@ void Sema::notePreviousDefinition(const NamedDecl *Old, SourceLocation New) {
// Is it the same file and same offset? Provide more information on why
// this leads to a redefinition error.
- bool EmittedDiag = false;
if (FNew == FOld && FNewDecLoc.second == FOldDecLoc.second) {
SourceLocation OldIncLoc = SrcMgr.getIncludeLoc(FOldDecLoc.first);
SourceLocation NewIncLoc = SrcMgr.getIncludeLoc(FNewDecLoc.first);
- EmittedDiag = noteFromModuleOrInclude(Old->getOwningModule(), OldIncLoc);
+ bool EmittedDiag =
+ noteFromModuleOrInclude(Old->getOwningModule(), OldIncLoc);
EmittedDiag |= noteFromModuleOrInclude(getCurrentModule(), NewIncLoc);
// If the header has no guards, emit a note suggesting one.
@@ -4175,9 +4336,11 @@ void Sema::handleTagNumbering(const TagDecl *Tag, Scope *TagScope) {
}
// If this tag isn't a direct child of a class, number it if it is local.
+ MangleNumberingContext *MCtx;
Decl *ManglingContextDecl;
- if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext(
- Tag->getDeclContext(), ManglingContextDecl)) {
+ std::tie(MCtx, ManglingContextDecl) =
+ getCurrentMangleNumberContext(Tag->getDeclContext());
+ if (MCtx) {
Context.setManglingNumber(
Tag, MCtx->getManglingNumber(
Tag, getMSManglingNumber(getLangOpts(), TagScope)));
@@ -4299,13 +4462,13 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
// and definitions of functions and variables.
// C++2a [dcl.constexpr]p1: The consteval specifier shall be applied only to
// the declaration of a function or function template
- bool IsConsteval = DS.getConstexprSpecifier() == CSK_consteval;
if (Tag)
Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag)
- << GetDiagnosticTypeSpecifierID(DS.getTypeSpecType()) << IsConsteval;
+ << GetDiagnosticTypeSpecifierID(DS.getTypeSpecType())
+ << DS.getConstexprSpecifier();
else
Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_wrong_decl_kind)
- << IsConsteval;
+ << DS.getConstexprSpecifier();
// Don't emit warnings after this error.
return TagD;
}
@@ -4497,7 +4660,7 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
TypeSpecType == DeclSpec::TST_enum) {
for (const ParsedAttr &AL : DS.getAttributes())
Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored)
- << AL.getName() << GetDiagnosticTypeSpecifierID(TypeSpecType);
+ << AL << GetDiagnosticTypeSpecifierID(TypeSpecType);
}
}
@@ -4686,12 +4849,12 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
bool Invalid = false;
if (getLangOpts().CPlusPlus) {
const char *PrevSpec = nullptr;
- unsigned DiagID;
if (Record->isUnion()) {
// C++ [class.union]p6:
// C++17 [class.union.anon]p2:
// Anonymous unions declared in a named namespace or in the
// global namespace shall be declared static.
+ unsigned DiagID;
DeclContext *OwnerScope = Owner->getRedeclContext();
if (DS.getStorageClassSpec() != DeclSpec::SCS_static &&
(OwnerScope->isTranslationUnit() ||
@@ -4913,9 +5076,11 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
if (VarDecl *NewVD = dyn_cast<VarDecl>(Anon)) {
if (getLangOpts().CPlusPlus && NewVD->isStaticLocal()) {
+ MangleNumberingContext *MCtx;
Decl *ManglingContextDecl;
- if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext(
- NewVD->getDeclContext(), ManglingContextDecl)) {
+ std::tie(MCtx, ManglingContextDecl) =
+ getCurrentMangleNumberContext(NewVD->getDeclContext());
+ if (MCtx) {
Context.setManglingNumber(
NewVD, MCtx->getManglingNumber(
NewVD, getMSManglingNumber(getLangOpts(), S)));
@@ -5649,8 +5814,8 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
return QualType();
}
- return Context.getConstantArrayType(VLATy->getElementType(),
- Res, ArrayType::Normal, 0);
+ return Context.getConstantArrayType(
+ VLATy->getElementType(), Res, VLATy->getSizeExpr(), ArrayType::Normal, 0);
}
static void
@@ -5760,7 +5925,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
<< getLangOpts().CPlusPlus17;
if (D.getDeclSpec().hasConstexprSpecifier())
Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)
- << 1 << (D.getDeclSpec().getConstexprSpecifier() == CSK_consteval);
+ << 1 << D.getDeclSpec().getConstexprSpecifier();
if (D.getName().Kind != UnqualifiedIdKind::IK_Identifier) {
if (D.getName().Kind == UnqualifiedIdKind::IK_DeductionGuideName)
@@ -5842,6 +6007,8 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
if (!Previous.empty()) {
Redeclaration = true;
MergeTypedefNameDecl(S, NewTD, Previous);
+ } else {
+ inferGslPointerAttribute(NewTD);
}
if (ShadowedDecl && !Redeclaration)
@@ -6171,9 +6338,8 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
<< NewDecl;
S.Diag(OldDecl->getLocation(), diag::note_previous_declaration);
NewDecl->dropAttr<DLLImportAttr>();
- NewDecl->addAttr(::new (S.Context) DLLExportAttr(
- NewImportAttr->getRange(), S.Context,
- NewImportAttr->getSpellingListIndex()));
+ NewDecl->addAttr(
+ DLLExportAttr::CreateImplicit(S.Context, NewImportAttr->getRange()));
} else {
S.Diag(NewDecl->getLocation(),
diag::warn_redeclaration_without_attribute_prev_attribute_ignored)
@@ -6658,19 +6824,6 @@ NamedDecl *Sema::ActOnVariableDeclarator(
if (TemplateParamLists.size() > VDTemplateParamLists)
NewVD->setTemplateParameterListsInfo(
Context, TemplateParamLists.drop_back(VDTemplateParamLists));
-
- if (D.getDeclSpec().hasConstexprSpecifier()) {
- NewVD->setConstexpr(true);
- // C++1z [dcl.spec.constexpr]p1:
- // A static data member declared with the constexpr specifier is
- // implicitly an inline variable.
- if (NewVD->isStaticDataMember() && getLangOpts().CPlusPlus17)
- NewVD->setImplicitlyInline();
- if (D.getDeclSpec().getConstexprSpecifier() == CSK_consteval)
- Diag(D.getDeclSpec().getConstexprSpecLoc(),
- diag::err_constexpr_wrong_decl_kind)
- << /*consteval*/ 1;
- }
}
if (D.getDeclSpec().isInlineSpecified()) {
@@ -6736,6 +6889,38 @@ NamedDecl *Sema::ActOnVariableDeclarator(
NewVD->setTSCSpec(TSCS);
}
+ switch (D.getDeclSpec().getConstexprSpecifier()) {
+ case CSK_unspecified:
+ break;
+
+ case CSK_consteval:
+ Diag(D.getDeclSpec().getConstexprSpecLoc(),
+ diag::err_constexpr_wrong_decl_kind)
+ << D.getDeclSpec().getConstexprSpecifier();
+ LLVM_FALLTHROUGH;
+
+ case CSK_constexpr:
+ NewVD->setConstexpr(true);
+ // C++1z [dcl.spec.constexpr]p1:
+ // A static data member declared with the constexpr specifier is
+ // implicitly an inline variable.
+ if (NewVD->isStaticDataMember() &&
+ (getLangOpts().CPlusPlus17 ||
+ Context.getTargetInfo().getCXXABI().isMicrosoft()))
+ NewVD->setImplicitlyInline();
+ break;
+
+ case CSK_constinit:
+ if (!NewVD->hasGlobalStorage())
+ Diag(D.getDeclSpec().getConstexprSpecLoc(),
+ diag::err_constinit_local_variable);
+ else
+ NewVD->addAttr(ConstInitAttr::Create(
+ Context, D.getDeclSpec().getConstexprSpecLoc(),
+ AttributeCommonInfo::AS_Keyword, ConstInitAttr::Keyword_constinit));
+ break;
+ }
+
// C99 6.7.4p3
// An inline definition of a function with external linkage shall
// not contain a definition of a modifiable object with static or
@@ -6786,7 +6971,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
if (EmitTLSUnsupportedError &&
((getLangOpts().CUDA && DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) ||
(getLangOpts().OpenMPIsDevice &&
- NewVD->hasAttr<OMPDeclareTargetDeclAttr>())))
+ OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(NewVD))))
Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
diag::err_thread_unsupported);
// CUDA B.2.5: "__shared__ and __constant__ variables have implied static
@@ -6854,8 +7039,8 @@ NamedDecl *Sema::ActOnVariableDeclarator(
}
}
- NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0),
- Context, Label, 0));
+ NewVD->addAttr(::new (Context) AsmLabelAttr(
+ Context, SE->getStrTokenLoc(0), Label, /*IsLiteralLabel=*/true));
} else if (!ExtnameUndeclaredIdentifiers.empty()) {
llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier());
@@ -6961,9 +7146,11 @@ NamedDecl *Sema::ActOnVariableDeclarator(
RegisterLocallyScopedExternCDecl(NewVD, S);
if (getLangOpts().CPlusPlus && NewVD->isStaticLocal()) {
+ MangleNumberingContext *MCtx;
Decl *ManglingContextDecl;
- if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext(
- NewVD->getDeclContext(), ManglingContextDecl)) {
+ std::tie(MCtx, ManglingContextDecl) =
+ getCurrentMangleNumberContext(NewVD->getDeclContext());
+ if (MCtx) {
Context.setManglingNumber(
NewVD, MCtx->getManglingNumber(
NewVD, getMSManglingNumber(getLangOpts(), S)));
@@ -7638,7 +7825,7 @@ struct FindOverriddenMethod {
/// CXXRecordDecl::lookupInBases().
bool operator()(const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
RecordDecl *BaseRecord =
- Specifier->getType()->getAs<RecordType>()->getDecl();
+ Specifier->getType()->castAs<RecordType>()->getDecl();
DeclarationName Name = Method->getDeclName();
@@ -7772,7 +7959,7 @@ class DifferentNameValidatorCCC final : public CorrectionCandidateCallback {
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<DifferentNameValidatorCCC>(*this);
+ return std::make_unique<DifferentNameValidatorCCC>(*this);
}
private:
@@ -7976,7 +8163,7 @@ static StorageClass getFunctionStorageClass(Sema &SemaRef, Declarator &D) {
return SC_None;
}
-static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
+static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
DeclContext *DC, QualType &R,
TypeSourceInfo *TInfo,
StorageClass SC,
@@ -8008,13 +8195,22 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
}
ExplicitSpecifier ExplicitSpecifier = D.getDeclSpec().getExplicitSpecifier();
+
ConstexprSpecKind ConstexprKind = D.getDeclSpec().getConstexprSpecifier();
+ if (ConstexprKind == CSK_constinit) {
+ SemaRef.Diag(D.getDeclSpec().getConstexprSpecLoc(),
+ diag::err_constexpr_wrong_decl_kind)
+ << ConstexprKind;
+ ConstexprKind = CSK_unspecified;
+ D.getMutableDeclSpec().ClearConstexprSpec();
+ }
+
// Check that the return type is not an abstract class type.
// For record types, this is done by the AbstractClassUsageDiagnoser once
// the class has been completely parsed.
if (!DC->isRecord() &&
SemaRef.RequireNonAbstractType(
- D.getIdentifierLoc(), R->getAs<FunctionType>()->getReturnType(),
+ D.getIdentifierLoc(), R->castAs<FunctionType>()->getReturnType(),
diag::err_abstract_type_in_decl, SemaRef.AbstractReturnType))
D.setInvalidType();
@@ -8034,10 +8230,10 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
if (DC->isRecord()) {
R = SemaRef.CheckDestructorDeclarator(D, R, SC);
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
- CXXDestructorDecl *NewDD =
- CXXDestructorDecl::Create(SemaRef.Context, Record, D.getBeginLoc(),
- NameInfo, R, TInfo, isInline,
- /*isImplicitlyDeclared=*/false);
+ CXXDestructorDecl *NewDD = CXXDestructorDecl::Create(
+ SemaRef.Context, Record, D.getBeginLoc(), NameInfo, R, TInfo,
+ isInline,
+ /*isImplicitlyDeclared=*/false, ConstexprKind);
// If the destructor needs an implicit exception specification, set it
// now. FIXME: It'd be nice to be able to create the right type to start
@@ -8068,6 +8264,9 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
}
SemaRef.CheckConversionDeclarator(D, R, SC);
+ if (D.isInvalidType())
+ return nullptr;
+
IsVirtualOkay = true;
return CXXConversionDecl::Create(
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
@@ -8439,7 +8638,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool isInline = D.getDeclSpec().isInlineSpecified();
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier();
- ConstexprSpecKind ConstexprKind = D.getDeclSpec().getConstexprSpecifier();
isFriend = D.getDeclSpec().isFriendSpecified();
if (isFriend && !isInline && D.isFunctionDefinition()) {
// C++ [class.friend]p5
@@ -8638,7 +8836,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
- if (ConstexprKind != CSK_unspecified) {
+ if (ConstexprSpecKind ConstexprKind =
+ D.getDeclSpec().getConstexprSpecifier()) {
// C++11 [dcl.constexpr]p2: constexpr functions and constexpr constructors
// are implicitly inline.
NewFD->setImplicitlyInline();
@@ -8646,9 +8845,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// C++11 [dcl.constexpr]p3: functions declared constexpr are required to
// be either constructors or to return a literal type. Therefore,
// destructors cannot be declared constexpr.
- if (isa<CXXDestructorDecl>(NewFD))
+ if (isa<CXXDestructorDecl>(NewFD) && !getLangOpts().CPlusPlus2a) {
Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor)
- << (ConstexprKind == CSK_consteval);
+ << ConstexprKind;
+ }
}
// If __module_private__ was specified, mark the function accordingly.
@@ -8743,8 +8943,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (Expr *E = (Expr*) D.getAsmLabel()) {
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
- NewFD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), Context,
- SE->getString(), 0));
+ NewFD->addAttr(::new (Context)
+ AsmLabelAttr(Context, SE->getStrTokenLoc(0),
+ SE->getString(), /*IsLiteralLabel=*/true));
} else if (!ExtnameUndeclaredIdentifiers.empty()) {
llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
ExtnameUndeclaredIdentifiers.find(NewFD->getIdentifier());
@@ -8842,9 +9043,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setParams(Params);
if (D.getDeclSpec().isNoreturnSpecified())
- NewFD->addAttr(
- ::new(Context) C11NoReturnAttr(D.getDeclSpec().getNoreturnSpecLoc(),
- Context, 0));
+ NewFD->addAttr(C11NoReturnAttr::Create(Context,
+ D.getDeclSpec().getNoreturnSpecLoc(),
+ AttributeCommonInfo::AS_Keyword));
// Functions returning a variably modified type violate C99 6.7.5.2p2
// because all functions have linkage.
@@ -8856,19 +9057,18 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Apply an implicit SectionAttr if '#pragma clang section text' is active
if (PragmaClangTextSection.Valid && D.isFunctionDefinition() &&
- !NewFD->hasAttr<SectionAttr>()) {
- NewFD->addAttr(PragmaClangTextSectionAttr::CreateImplicit(Context,
- PragmaClangTextSection.SectionName,
- PragmaClangTextSection.PragmaLocation));
- }
+ !NewFD->hasAttr<SectionAttr>())
+ NewFD->addAttr(PragmaClangTextSectionAttr::CreateImplicit(
+ Context, PragmaClangTextSection.SectionName,
+ PragmaClangTextSection.PragmaLocation, AttributeCommonInfo::AS_Pragma));
// Apply an implicit SectionAttr if #pragma code_seg is active.
if (CodeSegStack.CurrentValue && D.isFunctionDefinition() &&
!NewFD->hasAttr<SectionAttr>()) {
- NewFD->addAttr(
- SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate,
- CodeSegStack.CurrentValue->getString(),
- CodeSegStack.CurrentPragmaLocation));
+ NewFD->addAttr(SectionAttr::CreateImplicit(
+ Context, CodeSegStack.CurrentValue->getString(),
+ CodeSegStack.CurrentPragmaLocation, AttributeCommonInfo::AS_Pragma,
+ SectionAttr::Declspec_allocate));
if (UnifySection(CodeSegStack.CurrentValue->getString(),
ASTContext::PSF_Implicit | ASTContext::PSF_Execute |
ASTContext::PSF_Read,
@@ -8999,7 +9199,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// may end up with different effective targets. Instead, a
// specialization inherits its target attributes from its template
// in the CheckFunctionTemplateSpecialization() call below.
- if (getLangOpts().CUDA & !isFunctionTemplateSpecialization)
+ if (getLangOpts().CUDA && !isFunctionTemplateSpecialization)
maybeAddCUDAHostDeviceAttrs(NewFD, Previous);
// If it's a friend (and only if it's a friend), it's possible
@@ -9404,12 +9604,11 @@ Attr *Sema::getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD,
if (Attr *A = getImplicitCodeSegAttrFromClass(*this, FD))
return A;
if (!FD->hasAttr<SectionAttr>() && IsDefinition &&
- CodeSegStack.CurrentValue) {
- return SectionAttr::CreateImplicit(getASTContext(),
- SectionAttr::Declspec_allocate,
- CodeSegStack.CurrentValue->getString(),
- CodeSegStack.CurrentPragmaLocation);
- }
+ CodeSegStack.CurrentValue)
+ return SectionAttr::CreateImplicit(
+ getASTContext(), CodeSegStack.CurrentValue->getString(),
+ CodeSegStack.CurrentPragmaLocation, AttributeCommonInfo::AS_Pragma,
+ SectionAttr::Declspec_allocate);
return nullptr;
}
@@ -9538,10 +9737,13 @@ static bool HasNonMultiVersionAttributes(const FunctionDecl *FD,
return false;
}
-static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
- const FunctionDecl *NewFD,
- bool CausesMV,
- MultiVersionKind MVType) {
+bool Sema::areMultiversionVariantFunctionsCompatible(
+ const FunctionDecl *OldFD, const FunctionDecl *NewFD,
+ const PartialDiagnostic &NoProtoDiagID,
+ const PartialDiagnosticAt &NoteCausedDiagIDAt,
+ const PartialDiagnosticAt &NoSupportDiagIDAt,
+ const PartialDiagnosticAt &DiffDiagIDAt, bool TemplatesSupported,
+ bool ConstexprSupported, bool CLinkageMayDiffer) {
enum DoesntSupport {
FuncTemplates = 0,
VirtFuncs = 1,
@@ -9559,123 +9761,85 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
ConstexprSpec = 2,
InlineSpec = 3,
StorageClass = 4,
- Linkage = 5
+ Linkage = 5,
};
- bool IsCPUSpecificCPUDispatchMVType =
- MVType == MultiVersionKind::CPUDispatch ||
- MVType == MultiVersionKind::CPUSpecific;
-
if (OldFD && !OldFD->getType()->getAs<FunctionProtoType>()) {
- S.Diag(OldFD->getLocation(), diag::err_multiversion_noproto);
- S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
+ Diag(OldFD->getLocation(), NoProtoDiagID);
+ Diag(NoteCausedDiagIDAt.first, NoteCausedDiagIDAt.second);
return true;
}
if (!NewFD->getType()->getAs<FunctionProtoType>())
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_noproto);
+ return Diag(NewFD->getLocation(), NoProtoDiagID);
- if (!S.getASTContext().getTargetInfo().supportsMultiVersioning()) {
- S.Diag(NewFD->getLocation(), diag::err_multiversion_not_supported);
- if (OldFD)
- S.Diag(OldFD->getLocation(), diag::note_previous_declaration);
- return true;
- }
-
- // For now, disallow all other attributes. These should be opt-in, but
- // an analysis of all of them is a future FIXME.
- if (CausesMV && OldFD && HasNonMultiVersionAttributes(OldFD, MVType)) {
- S.Diag(OldFD->getLocation(), diag::err_multiversion_no_other_attrs)
- << IsCPUSpecificCPUDispatchMVType;
- S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
- return true;
- }
-
- if (HasNonMultiVersionAttributes(NewFD, MVType))
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_no_other_attrs)
- << IsCPUSpecificCPUDispatchMVType;
-
- if (NewFD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
- << IsCPUSpecificCPUDispatchMVType << FuncTemplates;
+ if (!TemplatesSupported &&
+ NewFD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
+ return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second)
+ << FuncTemplates;
if (const auto *NewCXXFD = dyn_cast<CXXMethodDecl>(NewFD)) {
if (NewCXXFD->isVirtual())
- return S.Diag(NewCXXFD->getLocation(),
- diag::err_multiversion_doesnt_support)
- << IsCPUSpecificCPUDispatchMVType << VirtFuncs;
+ return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second)
+ << VirtFuncs;
- if (const auto *NewCXXCtor = dyn_cast<CXXConstructorDecl>(NewFD))
- return S.Diag(NewCXXCtor->getLocation(),
- diag::err_multiversion_doesnt_support)
- << IsCPUSpecificCPUDispatchMVType << Constructors;
+ if (isa<CXXConstructorDecl>(NewCXXFD))
+ return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second)
+ << Constructors;
- if (const auto *NewCXXDtor = dyn_cast<CXXDestructorDecl>(NewFD))
- return S.Diag(NewCXXDtor->getLocation(),
- diag::err_multiversion_doesnt_support)
- << IsCPUSpecificCPUDispatchMVType << Destructors;
+ if (isa<CXXDestructorDecl>(NewCXXFD))
+ return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second)
+ << Destructors;
}
if (NewFD->isDeleted())
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
- << IsCPUSpecificCPUDispatchMVType << DeletedFuncs;
+ return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second)
+ << DeletedFuncs;
if (NewFD->isDefaulted())
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
- << IsCPUSpecificCPUDispatchMVType << DefaultedFuncs;
+ return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second)
+ << DefaultedFuncs;
- if (NewFD->isConstexpr() && (MVType == MultiVersionKind::CPUDispatch ||
- MVType == MultiVersionKind::CPUSpecific))
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
- << IsCPUSpecificCPUDispatchMVType
+ if (!ConstexprSupported && NewFD->isConstexpr())
+ return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second)
<< (NewFD->isConsteval() ? ConstevalFuncs : ConstexprFuncs);
- QualType NewQType = S.getASTContext().getCanonicalType(NewFD->getType());
+ QualType NewQType = Context.getCanonicalType(NewFD->getType());
const auto *NewType = cast<FunctionType>(NewQType);
QualType NewReturnType = NewType->getReturnType();
if (NewReturnType->isUndeducedType())
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
- << IsCPUSpecificCPUDispatchMVType << DeducedReturn;
-
- // Only allow transition to MultiVersion if it hasn't been used.
- if (OldFD && CausesMV && OldFD->isUsed(false))
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_after_used);
+ return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second)
+ << DeducedReturn;
// Ensure the return type is identical.
if (OldFD) {
- QualType OldQType = S.getASTContext().getCanonicalType(OldFD->getType());
+ QualType OldQType = Context.getCanonicalType(OldFD->getType());
const auto *OldType = cast<FunctionType>(OldQType);
FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo();
FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo();
if (OldTypeInfo.getCC() != NewTypeInfo.getCC())
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
- << CallingConv;
+ return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << CallingConv;
QualType OldReturnType = OldType->getReturnType();
if (OldReturnType != NewReturnType)
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
- << ReturnType;
+ return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << ReturnType;
if (OldFD->getConstexprKind() != NewFD->getConstexprKind())
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
- << ConstexprSpec;
+ return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << ConstexprSpec;
if (OldFD->isInlineSpecified() != NewFD->isInlineSpecified())
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
- << InlineSpec;
+ return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << InlineSpec;
if (OldFD->getStorageClass() != NewFD->getStorageClass())
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
- << StorageClass;
+ return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << StorageClass;
- if (OldFD->isExternC() != NewFD->isExternC())
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
- << Linkage;
+ if (!CLinkageMayDiffer && OldFD->isExternC() != NewFD->isExternC())
+ return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << Linkage;
- if (S.CheckEquivalentExceptionSpec(
+ if (CheckEquivalentExceptionSpec(
OldFD->getType()->getAs<FunctionProtoType>(), OldFD->getLocation(),
NewFD->getType()->getAs<FunctionProtoType>(), NewFD->getLocation()))
return true;
@@ -9683,6 +9847,52 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
return false;
}
+static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
+ const FunctionDecl *NewFD,
+ bool CausesMV,
+ MultiVersionKind MVType) {
+ if (!S.getASTContext().getTargetInfo().supportsMultiVersioning()) {
+ S.Diag(NewFD->getLocation(), diag::err_multiversion_not_supported);
+ if (OldFD)
+ S.Diag(OldFD->getLocation(), diag::note_previous_declaration);
+ return true;
+ }
+
+ bool IsCPUSpecificCPUDispatchMVType =
+ MVType == MultiVersionKind::CPUDispatch ||
+ MVType == MultiVersionKind::CPUSpecific;
+
+ // For now, disallow all other attributes. These should be opt-in, but
+ // an analysis of all of them is a future FIXME.
+ if (CausesMV && OldFD && HasNonMultiVersionAttributes(OldFD, MVType)) {
+ S.Diag(OldFD->getLocation(), diag::err_multiversion_no_other_attrs)
+ << IsCPUSpecificCPUDispatchMVType;
+ S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
+ return true;
+ }
+
+ if (HasNonMultiVersionAttributes(NewFD, MVType))
+ return S.Diag(NewFD->getLocation(), diag::err_multiversion_no_other_attrs)
+ << IsCPUSpecificCPUDispatchMVType;
+
+ // Only allow transition to MultiVersion if it hasn't been used.
+ if (OldFD && CausesMV && OldFD->isUsed(false))
+ return S.Diag(NewFD->getLocation(), diag::err_multiversion_after_used);
+
+ return S.areMultiversionVariantFunctionsCompatible(
+ OldFD, NewFD, S.PDiag(diag::err_multiversion_noproto),
+ PartialDiagnosticAt(NewFD->getLocation(),
+ S.PDiag(diag::note_multiversioning_caused_here)),
+ PartialDiagnosticAt(NewFD->getLocation(),
+ S.PDiag(diag::err_multiversion_doesnt_support)
+ << IsCPUSpecificCPUDispatchMVType),
+ PartialDiagnosticAt(NewFD->getLocation(),
+ S.PDiag(diag::err_multiversion_diff)),
+ /*TemplatesSupported=*/false,
+ /*ConstexprSupported=*/!IsCPUSpecificCPUDispatchMVType,
+ /*CLinkageMayDiffer=*/false);
+}
+
/// Check the validity of a multiversion function declaration that is the
/// first of its kind. Also sets the multiversion'ness' of the function itself.
///
@@ -10130,7 +10340,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
if (!getLangOpts().CPlusPlus14 && MD && MD->isConstexpr() &&
!MD->isStatic() && !isa<CXXConstructorDecl>(MD) &&
- !MD->getMethodQualifiers().hasConst()) {
+ !isa<CXXDestructorDecl>(MD) && !MD->getMethodQualifiers().hasConst()) {
CXXMethodDecl *OldMD = nullptr;
if (OldDecl)
OldMD = dyn_cast_or_null<CXXMethodDecl>(OldDecl->getAsFunction());
@@ -11120,6 +11330,15 @@ void Sema::checkNonTrivialCUnionInInitializer(const Expr *Init,
namespace {
+bool shouldIgnoreForRecordTriviality(const FieldDecl *FD) {
+ // Ignore unavailable fields. A field can be marked as unavailable explicitly
+ // in the source code or implicitly by the compiler if it is in a union
+ // defined in a system header and has non-trivial ObjC ownership
+ // qualifications. We don't want those fields to participate in determining
+ // whether the containing union is non-trivial.
+ return FD->hasAttr<UnavailableAttr>();
+}
+
struct DiagNonTrivalCUnionDefaultInitializeVisitor
: DefaultInitializedTypeVisitor<DiagNonTrivalCUnionDefaultInitializeVisitor,
void> {
@@ -11173,7 +11392,8 @@ struct DiagNonTrivalCUnionDefaultInitializeVisitor
<< 0 << 0 << QT.getUnqualifiedType() << "";
for (const FieldDecl *FD : RD->fields())
- asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
+ if (!shouldIgnoreForRecordTriviality(FD))
+ asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
}
void visitTrivial(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {}
@@ -11237,7 +11457,8 @@ struct DiagNonTrivalCUnionDestructedTypeVisitor
<< 0 << 1 << QT.getUnqualifiedType() << "";
for (const FieldDecl *FD : RD->fields())
- asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
+ if (!shouldIgnoreForRecordTriviality(FD))
+ asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
}
void visitTrivial(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {}
@@ -11302,7 +11523,8 @@ struct DiagNonTrivalCUnionCopyVisitor
<< 0 << 2 << QT.getUnqualifiedType() << "";
for (const FieldDecl *FD : RD->fields())
- asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
+ if (!shouldIgnoreForRecordTriviality(FD))
+ asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
}
void preVisit(QualType::PrimitiveCopyKind PCK, QualType QT,
@@ -11527,9 +11749,12 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
// Check for self-references within variable initializers.
// Variables declared within a function/method body (except for references)
// are handled by a dataflow analysis.
- if (!VDecl->hasLocalStorage() || VDecl->getType()->isRecordType() ||
- VDecl->getType()->isReferenceType()) {
- CheckSelfReference(*this, RealDecl, Init, DirectInit);
+ // This is undefined behavior in C++, but valid in C.
+ if (getLangOpts().CPlusPlus) {
+ if (!VDecl->hasLocalStorage() || VDecl->getType()->isRecordType() ||
+ VDecl->getType()->isReferenceType()) {
+ CheckSelfReference(*this, RealDecl, Init, DirectInit);
+ }
}
// If the type changed, it means we had an incomplete type that was
@@ -11853,7 +12078,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
if (Var->isStaticDataMember()) {
// C++1z removes the relevant rule; the in-class declaration is always
// a definition there.
- if (!getLangOpts().CPlusPlus17) {
+ if (!getLangOpts().CPlusPlus17 &&
+ !Context.getTargetInfo().getCXXABI().isMicrosoft()) {
Diag(Var->getLocation(),
diag::err_constexpr_static_mem_var_requires_init)
<< Var->getDeclName();
@@ -12239,11 +12465,11 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
Stack = &DataSegStack;
SectionFlags |= ASTContext::PSF_Write;
}
- if (Stack->CurrentValue && !var->hasAttr<SectionAttr>()) {
+ if (Stack->CurrentValue && !var->hasAttr<SectionAttr>())
var->addAttr(SectionAttr::CreateImplicit(
- Context, SectionAttr::Declspec_allocate,
- Stack->CurrentValue->getString(), Stack->CurrentPragmaLocation));
- }
+ Context, Stack->CurrentValue->getString(),
+ Stack->CurrentPragmaLocation, AttributeCommonInfo::AS_Pragma,
+ SectionAttr::Declspec_allocate));
if (const SectionAttr *SA = var->getAttr<SectionAttr>())
if (UnifySection(SA->getName(), SectionFlags, var))
var->dropAttr<SectionAttr>();
@@ -12253,7 +12479,8 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
// attribute.
if (CurInitSeg && var->getInit())
var->addAttr(InitSegAttr::CreateImplicit(Context, CurInitSeg->getString(),
- CurInitSegLoc));
+ CurInitSegLoc,
+ AttributeCommonInfo::AS_Pragma));
}
// All the following checks are C++ only.
@@ -12304,17 +12531,17 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
// Don't emit further diagnostics about constexpr globals since they
// were just diagnosed.
- if (!var->isConstexpr() && GlobalStorage &&
- var->hasAttr<RequireConstantInitAttr>()) {
+ if (!var->isConstexpr() && GlobalStorage && var->hasAttr<ConstInitAttr>()) {
// FIXME: Need strict checking in C++03 here.
bool DiagErr = getLangOpts().CPlusPlus11
? !var->checkInitIsICE() : !checkConstInit();
if (DiagErr) {
- auto attr = var->getAttr<RequireConstantInitAttr>();
+ auto *Attr = var->getAttr<ConstInitAttr>();
Diag(var->getLocation(), diag::err_require_constant_init_failed)
<< Init->getSourceRange();
- Diag(attr->getLocation(), diag::note_declared_required_constant_init_here)
- << attr->getRange();
+ Diag(Attr->getLocation(),
+ diag::note_declared_required_constant_init_here)
+ << Attr->getRange() << Attr->isConstinit();
if (getLangOpts().CPlusPlus11) {
APValue Value;
SmallVector<PartialDiagnosticAt, 8> Notes;
@@ -12386,9 +12613,7 @@ void Sema::CheckStaticLocalForDllExport(VarDecl *VD) {
NewAttr->setInherited(true);
VD->addAttr(NewAttr);
} else if (Attr *A = FD->getAttr<DLLExportStaticLocalAttr>()) {
- auto *NewAttr = ::new (getASTContext()) DLLExportAttr(A->getRange(),
- getASTContext(),
- A->getSpellingListIndex());
+ auto *NewAttr = DLLExportAttr::CreateImplicit(getASTContext(), *A);
NewAttr->setInherited(true);
VD->addAttr(NewAttr);
@@ -12398,9 +12623,7 @@ void Sema::CheckStaticLocalForDllExport(VarDecl *VD) {
FD->addAttr(NewAttr);
} else if (Attr *A = FD->getAttr<DLLImportStaticLocalAttr>()) {
- auto *NewAttr = ::new (getASTContext()) DLLImportAttr(A->getRange(),
- getASTContext(),
- A->getSpellingListIndex());
+ auto *NewAttr = DLLImportAttr::CreateImplicit(getASTContext(), *A);
NewAttr->setInherited(true);
VD->addAttr(NewAttr);
}
@@ -12420,17 +12643,25 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) {
if (VD->hasGlobalStorage() && VD->isThisDeclarationADefinition() &&
!inTemplateInstantiation() && !VD->hasAttr<SectionAttr>()) {
if (PragmaClangBSSSection.Valid)
- VD->addAttr(PragmaClangBSSSectionAttr::CreateImplicit(Context,
- PragmaClangBSSSection.SectionName,
- PragmaClangBSSSection.PragmaLocation));
+ VD->addAttr(PragmaClangBSSSectionAttr::CreateImplicit(
+ Context, PragmaClangBSSSection.SectionName,
+ PragmaClangBSSSection.PragmaLocation,
+ AttributeCommonInfo::AS_Pragma));
if (PragmaClangDataSection.Valid)
- VD->addAttr(PragmaClangDataSectionAttr::CreateImplicit(Context,
- PragmaClangDataSection.SectionName,
- PragmaClangDataSection.PragmaLocation));
+ VD->addAttr(PragmaClangDataSectionAttr::CreateImplicit(
+ Context, PragmaClangDataSection.SectionName,
+ PragmaClangDataSection.PragmaLocation,
+ AttributeCommonInfo::AS_Pragma));
if (PragmaClangRodataSection.Valid)
- VD->addAttr(PragmaClangRodataSectionAttr::CreateImplicit(Context,
- PragmaClangRodataSection.SectionName,
- PragmaClangRodataSection.PragmaLocation));
+ VD->addAttr(PragmaClangRodataSectionAttr::CreateImplicit(
+ Context, PragmaClangRodataSection.SectionName,
+ PragmaClangRodataSection.PragmaLocation,
+ AttributeCommonInfo::AS_Pragma));
+ if (PragmaClangRelroSection.Valid)
+ VD->addAttr(PragmaClangRelroSectionAttr::CreateImplicit(
+ Context, PragmaClangRelroSection.SectionName,
+ PragmaClangRelroSection.PragmaLocation,
+ AttributeCommonInfo::AS_Pragma));
}
if (auto *DD = dyn_cast<DecompositionDecl>(ThisDecl)) {
@@ -12726,20 +12957,10 @@ void Sema::ActOnDocumentableDecls(ArrayRef<Decl *> Group) {
}
}
- // See if there are any new comments that are not attached to a decl.
- ArrayRef<RawComment *> Comments = Context.getRawCommentList().getComments();
- if (!Comments.empty() &&
- !Comments.back()->isAttached()) {
- // There is at least one comment that not attached to a decl.
- // Maybe it should be attached to one of these decls?
- //
- // Note that this way we pick up not only comments that precede the
- // declaration, but also comments that *follow* the declaration -- thanks to
- // the lookahead in the lexer: we've consumed the semicolon and looked
- // ahead through comments.
- for (unsigned i = 0, e = Group.size(); i != e; ++i)
- Context.getCommentForDecl(Group[i], &PP);
- }
+ // FIMXE: We assume every Decl in the group is in the same file.
+ // This is false when preprocessor constructs the group from decls in
+ // different files (e. g. macros or #include).
+ Context.attachCommentsToJustParsedDecls(Group, &getPreprocessor());
}
/// Common checks for a parameter-declaration that should apply to both function
@@ -12817,7 +13038,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
<< getLangOpts().CPlusPlus17;
if (DS.hasConstexprSpecifier())
Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr)
- << 0 << (D.getDeclSpec().getConstexprSpecifier() == CSK_consteval);
+ << 0 << D.getDeclSpec().getConstexprSpecifier();
DiagnoseFunctionSpecifiers(DS);
@@ -12977,6 +13198,13 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
Context.getAdjustedParameterType(T),
TSInfo, SC, nullptr);
+ // Make a note if we created a new pack in the scope of a lambda, so that
+ // we know that references to that pack must also be expanded within the
+ // lambda scope.
+ if (New->isParameterPack())
+ if (auto *LSI = getEnclosingLambda())
+ LSI->LocalPacks.push_back(New);
+
if (New->getType().hasNonTrivialToPrimitiveDestructCUnion() ||
New->getType().hasNonTrivialToPrimitiveCopyCUnion())
checkNonTrivialCUnion(New->getType(), New->getLocation(),
@@ -13817,8 +14045,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
}
if (!IsInstantiation && FD && FD->isConstexpr() && !FD->isInvalidDecl() &&
- (!CheckConstexprFunctionDecl(FD) ||
- !CheckConstexprFunctionBody(FD, Body)))
+ !CheckConstexprFunctionDefinition(FD, CheckConstexprKind::Diagnose))
FD->setInvalidDecl();
if (FD && FD->hasAttr<NakedAttr>()) {
@@ -14577,7 +14804,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
UPPC_FixedUnderlyingType))
EnumUnderlying = Context.IntTy.getTypePtr();
- } else if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ } else if (Context.getTargetInfo().getTriple().isWindowsMSVCEnvironment()) {
// For MSVC ABI compatibility, unfixed enums must use an underlying type
// of 'int'. However, if this is an unfixed forward declaration, don't set
// the underlying type unless the user enables -fms-compatibility. This
@@ -15400,6 +15627,9 @@ CreateNewDecl:
if (PrevDecl)
mergeDeclAttributes(New, PrevDecl);
+ if (auto *CXXRD = dyn_cast<CXXRecordDecl>(New))
+ inferGslOwnerPointerAttribute(CXXRD);
+
// If there's a #pragma GCC visibility in scope, set the visibility of this
// record.
AddPushedVisibilityAttribute(New);
@@ -15469,8 +15699,9 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD,
return;
if (FinalLoc.isValid())
- Record->addAttr(new (Context)
- FinalAttr(FinalLoc, Context, IsFinalSpelledSealed));
+ Record->addAttr(FinalAttr::Create(
+ Context, FinalLoc, AttributeCommonInfo::AS_Keyword,
+ static_cast<FinalAttr::Spelling>(IsFinalSpelledSealed)));
// C++ [class]p2:
// [...] The class-name is also inserted into the scope of the
@@ -16372,6 +16603,21 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
<< FixItHint::CreateInsertion(FD->getLocation(), "*");
QualType T = Context.getObjCObjectPointerType(FD->getType());
FD->setType(T);
+ } else if (Record && Record->isUnion() &&
+ FD->getType().hasNonTrivialObjCLifetime() &&
+ getSourceManager().isInSystemHeader(FD->getLocation()) &&
+ !getLangOpts().CPlusPlus && !FD->hasAttr<UnavailableAttr>() &&
+ (FD->getType().getObjCLifetime() != Qualifiers::OCL_Strong ||
+ !Context.hasDirectOwnershipQualifier(FD->getType()))) {
+ // For backward compatibility, fields of C unions declared in system
+ // headers that have non-trivial ObjC ownership qualifications are marked
+ // as unavailable unless the qualifier is explicit and __strong. This can
+ // break ABI compatibility between programs compiled with ARC and MRR, but
+ // is a better option than rejecting programs using those unions under
+ // ARC.
+ FD->addAttr(UnavailableAttr::CreateImplicit(
+ Context, "", UnavailableAttr::IR_ARCFieldWithOwnership,
+ FD->getLocation()));
} else if (getLangOpts().ObjC &&
getLangOpts().getGC() != LangOptions::NonGC &&
Record && !Record->hasObjectMember()) {
@@ -16381,7 +16627,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
else if (Context.getAsArrayType(FD->getType())) {
QualType BaseType = Context.getBaseElementType(FD->getType());
if (BaseType->isRecordType() &&
- BaseType->getAs<RecordType>()->getDecl()->hasObjectMember())
+ BaseType->castAs<RecordType>()->getDecl()->hasObjectMember())
Record->setHasObjectMember(true);
else if (BaseType->isObjCObjectPointerType() ||
BaseType.isObjCGCStrong())
@@ -16389,7 +16635,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
}
}
- if (Record && !getLangOpts().CPlusPlus && !FD->hasAttr<UnavailableAttr>()) {
+ if (Record && !getLangOpts().CPlusPlus &&
+ !shouldIgnoreForRecordTriviality(FD)) {
QualType FT = FD->getType();
if (FT.isNonTrivialToPrimitiveDefaultInitialize()) {
Record->setNonTrivialToPrimitiveDefaultInitialize(true);
@@ -16685,8 +16932,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
if (Enum->isDependentType() || Val->isTypeDependent())
EltTy = Context.DependentTy;
else {
- if (getLangOpts().CPlusPlus11 && Enum->isFixed() &&
- !getLangOpts().MSVCCompat) {
+ if (getLangOpts().CPlusPlus11 && Enum->isFixed()) {
// C++11 [dcl.enum]p5: If the underlying type is fixed, [...] the
// constant-expression in the enumerator-definition shall be a converted
// constant expression of the underlying type.
@@ -16711,15 +16957,19 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// we perform a non-narrowing conversion as part of converted constant
// expression checking.
if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
- if (getLangOpts().MSVCCompat) {
+ if (Context.getTargetInfo()
+ .getTriple()
+ .isWindowsMSVCEnvironment()) {
Diag(IdLoc, diag::ext_enumerator_too_large) << EltTy;
- Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).get();
- } else
+ } else {
Diag(IdLoc, diag::err_enumerator_too_large) << EltTy;
- } else
- Val = ImpCastExprToType(Val, EltTy,
- EltTy->isBooleanType() ?
- CK_IntegralToBoolean : CK_IntegralCast)
+ }
+ }
+
+ // Cast to the underlying type.
+ Val = ImpCastExprToType(Val, EltTy,
+ EltTy->isBooleanType() ? CK_IntegralToBoolean
+ : CK_IntegralCast)
.get();
} else if (getLangOpts().CPlusPlus) {
// C++11 [dcl.enum]p5:
@@ -17047,7 +17297,7 @@ static void CheckForDuplicateEnumValues(Sema &S, ArrayRef<Decl *> Elements,
continue;
// Create new vector and push values onto it.
- auto Vec = llvm::make_unique<ECDVector>();
+ auto Vec = std::make_unique<ECDVector>();
Vec->push_back(D);
Vec->push_back(ECD);
@@ -17371,8 +17621,10 @@ void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
SourceLocation AliasNameLoc) {
NamedDecl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc,
LookupOrdinaryName);
- AsmLabelAttr *Attr =
- AsmLabelAttr::CreateImplicit(Context, AliasName->getName(), AliasNameLoc);
+ AttributeCommonInfo Info(AliasName, SourceRange(AliasNameLoc),
+ AttributeCommonInfo::AS_Pragma);
+ AsmLabelAttr *Attr = AsmLabelAttr::CreateImplicit(
+ Context, AliasName->getName(), /*LiteralLabel=*/true, Info);
// If a declaration that:
// 1) declares a function or a variable
@@ -17395,7 +17647,7 @@ void Sema::ActOnPragmaWeakID(IdentifierInfo* Name,
Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName);
if (PrevDecl) {
- PrevDecl->addAttr(WeakAttr::CreateImplicit(Context, PragmaLoc));
+ PrevDecl->addAttr(WeakAttr::CreateImplicit(Context, PragmaLoc, AttributeCommonInfo::AS_Pragma));
} else {
(void)WeakUndeclaredIdentifiers.insert(
std::pair<IdentifierInfo*,WeakInfo>
@@ -17425,3 +17677,87 @@ void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name,
Decl *Sema::getObjCDeclContext() const {
return (dyn_cast_or_null<ObjCContainerDecl>(CurContext));
}
+
+Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD) {
+ // Templates are emitted when they're instantiated.
+ if (FD->isDependentContext())
+ return FunctionEmissionStatus::TemplateDiscarded;
+
+ FunctionEmissionStatus OMPES = FunctionEmissionStatus::Unknown;
+ if (LangOpts.OpenMPIsDevice) {
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl());
+ if (DevTy.hasValue()) {
+ if (*DevTy == OMPDeclareTargetDeclAttr::DT_Host)
+ OMPES = FunctionEmissionStatus::OMPDiscarded;
+ else if (DeviceKnownEmittedFns.count(FD) > 0)
+ OMPES = FunctionEmissionStatus::Emitted;
+ }
+ } else if (LangOpts.OpenMP) {
+ // In OpenMP 4.5 all the functions are host functions.
+ if (LangOpts.OpenMP <= 45) {
+ OMPES = FunctionEmissionStatus::Emitted;
+ } else {
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl());
+ // In OpenMP 5.0 or above, DevTy may be changed later by
+ // #pragma omp declare target to(*) device_type(*). Therefore DevTy
+ // having no value does not imply host. The emission status will be
+ // checked again at the end of compilation unit.
+ if (DevTy.hasValue()) {
+ if (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) {
+ OMPES = FunctionEmissionStatus::OMPDiscarded;
+ } else if (DeviceKnownEmittedFns.count(FD) > 0) {
+ OMPES = FunctionEmissionStatus::Emitted;
+ }
+ }
+ }
+ }
+ if (OMPES == FunctionEmissionStatus::OMPDiscarded ||
+ (OMPES == FunctionEmissionStatus::Emitted && !LangOpts.CUDA))
+ return OMPES;
+
+ if (LangOpts.CUDA) {
+ // When compiling for device, host functions are never emitted. Similarly,
+ // when compiling for host, device and global functions are never emitted.
+ // (Technically, we do emit a host-side stub for global functions, but this
+ // doesn't count for our purposes here.)
+ Sema::CUDAFunctionTarget T = IdentifyCUDATarget(FD);
+ if (LangOpts.CUDAIsDevice && T == Sema::CFT_Host)
+ return FunctionEmissionStatus::CUDADiscarded;
+ if (!LangOpts.CUDAIsDevice &&
+ (T == Sema::CFT_Device || T == Sema::CFT_Global))
+ return FunctionEmissionStatus::CUDADiscarded;
+
+ // Check whether this function is externally visible -- if so, it's
+ // known-emitted.
+ //
+ // We have to check the GVA linkage of the function's *definition* -- if we
+ // only have a declaration, we don't know whether or not the function will
+ // be emitted, because (say) the definition could include "inline".
+ FunctionDecl *Def = FD->getDefinition();
+
+ if (Def &&
+ !isDiscardableGVALinkage(getASTContext().GetGVALinkageForFunction(Def))
+ && (!LangOpts.OpenMP || OMPES == FunctionEmissionStatus::Emitted))
+ return FunctionEmissionStatus::Emitted;
+ }
+
+ // Otherwise, the function is known-emitted if it's in our set of
+ // known-emitted functions.
+ return (DeviceKnownEmittedFns.count(FD) > 0)
+ ? FunctionEmissionStatus::Emitted
+ : FunctionEmissionStatus::Unknown;
+}
+
+bool Sema::shouldIgnoreInHostDeviceCheck(FunctionDecl *Callee) {
+ // Host-side references to a __global__ function refer to the stub, so the
+ // function itself is never emitted and therefore should not be marked.
+ // If we have host fn calls kernel fn calls host+device, the HD function
+ // does not get instantiated on the host. We model this by omitting at the
+ // call to the kernel from the callgraph. This ensures that, when compiling
+ // for host, only HD functions actually called from the host get marked as
+ // known-emitted.
+ return LangOpts.CUDA && !LangOpts.CUDAIsDevice &&
+ IdentifyCUDATarget(Callee) == CFT_Global;
+}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index ee06f8ae5114..b2be6245a814 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -398,18 +398,11 @@ bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum,
/// Applies the given attribute to the Decl without performing any
/// additional semantic checking.
template <typename AttrType>
-static void handleSimpleAttribute(Sema &S, Decl *D, SourceRange SR,
- unsigned SpellingIndex) {
- D->addAttr(::new (S.Context) AttrType(SR, S.Context, SpellingIndex));
+static void handleSimpleAttribute(Sema &S, Decl *D,
+ const AttributeCommonInfo &CI) {
+ D->addAttr(::new (S.Context) AttrType(S.Context, CI));
}
-template <typename AttrType>
-static void handleSimpleAttribute(Sema &S, Decl *D, const ParsedAttr &AL) {
- handleSimpleAttribute<AttrType>(S, D, AL.getRange(),
- AL.getAttributeSpellingListIndex());
-}
-
-
template <typename... DiagnosticArgs>
static const Sema::SemaDiagnosticBuilder&
appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr) {
@@ -429,28 +422,16 @@ appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr, T &&ExtraArg,
/// Otherwise, emit diagnostic {@code DiagID}, passing in all parameters
/// specified in {@code ExtraArgs}.
template <typename AttrType, typename... DiagnosticArgs>
-static void
-handleSimpleAttributeOrDiagnose(Sema &S, Decl *D, SourceRange SR,
- unsigned SpellingIndex,
- bool PassesCheck,
- unsigned DiagID, DiagnosticArgs&&... ExtraArgs) {
+static void handleSimpleAttributeOrDiagnose(Sema &S, Decl *D,
+ const AttributeCommonInfo &CI,
+ bool PassesCheck, unsigned DiagID,
+ DiagnosticArgs &&... ExtraArgs) {
if (!PassesCheck) {
Sema::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID);
appendDiagnostics(DB, std::forward<DiagnosticArgs>(ExtraArgs)...);
return;
}
- handleSimpleAttribute<AttrType>(S, D, SR, SpellingIndex);
-}
-
-template <typename AttrType, typename... DiagnosticArgs>
-static void
-handleSimpleAttributeOrDiagnose(Sema &S, Decl *D, const ParsedAttr &AL,
- bool PassesCheck,
- unsigned DiagID,
- DiagnosticArgs&&... ExtraArgs) {
- return handleSimpleAttributeOrDiagnose<AttrType>(
- S, D, AL.getRange(), AL.getAttributeSpellingListIndex(), PassesCheck,
- DiagID, std::forward<DiagnosticArgs>(ExtraArgs)...);
+ handleSimpleAttribute<AttrType>(S, D, CI);
}
template <typename AttrType>
@@ -566,7 +547,7 @@ static bool checkRecordDeclForAttr(const RecordDecl *RD) {
// If it's type-dependent, we assume it could have the attribute.
if (Ty.isDependentType())
return true;
- return Ty.getAs<RecordType>()->getDecl()->hasAttr<AttrType>();
+ return Ty.castAs<RecordType>()->getDecl()->hasAttr<AttrType>();
},
BPaths, true))
return true;
@@ -745,9 +726,7 @@ static void handlePtGuardedVarAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!threadSafetyCheckIsPointer(S, D, AL))
return;
- D->addAttr(::new (S.Context)
- PtGuardedVarAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) PtGuardedVarAttr(S.Context, AL));
}
static bool checkGuardedByAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
@@ -769,8 +748,7 @@ static void handleGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!checkGuardedByAttrCommon(S, D, AL, Arg))
return;
- D->addAttr(::new (S.Context) GuardedByAttr(
- AL.getRange(), S.Context, Arg, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) GuardedByAttr(S.Context, AL, Arg));
}
static void handlePtGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -781,8 +759,7 @@ static void handlePtGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!threadSafetyCheckIsPointer(S, D, AL))
return;
- D->addAttr(::new (S.Context) PtGuardedByAttr(
- AL.getRange(), S.Context, Arg, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) PtGuardedByAttr(S.Context, AL, Arg));
}
static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
@@ -811,9 +788,8 @@ static void handleAcquiredAfterAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context) AcquiredAfterAttr(
- AL.getRange(), S.Context, StartArg, Args.size(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ AcquiredAfterAttr(S.Context, AL, StartArg, Args.size()));
}
static void handleAcquiredBeforeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -822,9 +798,8 @@ static void handleAcquiredBeforeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context) AcquiredBeforeAttr(
- AL.getRange(), S.Context, StartArg, Args.size(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ AcquiredBeforeAttr(S.Context, AL, StartArg, Args.size()));
}
static bool checkLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
@@ -844,8 +819,7 @@ static void handleAssertSharedLockAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
unsigned Size = Args.size();
Expr **StartArg = Size == 0 ? nullptr : &Args[0];
D->addAttr(::new (S.Context)
- AssertSharedLockAttr(AL.getRange(), S.Context, StartArg, Size,
- AL.getAttributeSpellingListIndex()));
+ AssertSharedLockAttr(S.Context, AL, StartArg, Size));
}
static void handleAssertExclusiveLockAttr(Sema &S, Decl *D,
@@ -856,9 +830,8 @@ static void handleAssertExclusiveLockAttr(Sema &S, Decl *D,
unsigned Size = Args.size();
Expr **StartArg = Size == 0 ? nullptr : &Args[0];
- D->addAttr(::new (S.Context) AssertExclusiveLockAttr(
- AL.getRange(), S.Context, StartArg, Size,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ AssertExclusiveLockAttr(S.Context, AL, StartArg, Size));
}
/// Checks to be sure that the given parameter number is in bounds, and
@@ -919,8 +892,7 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
D->addAttr(::new (S.Context)
- AllocSizeAttr(AL.getRange(), S.Context, SizeArgNo, NumberArgNo,
- AL.getAttributeSpellingListIndex()));
+ AllocSizeAttr(S.Context, AL, SizeArgNo, NumberArgNo));
}
static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
@@ -947,8 +919,7 @@ static void handleSharedTrylockFunctionAttr(Sema &S, Decl *D,
return;
D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(
- AL.getRange(), S.Context, AL.getArgAsExpr(0), Args.data(), Args.size(),
- AL.getAttributeSpellingListIndex()));
+ S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size()));
}
static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D,
@@ -958,8 +929,7 @@ static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D,
return;
D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(
- AL.getRange(), S.Context, AL.getArgAsExpr(0), Args.data(),
- Args.size(), AL.getAttributeSpellingListIndex()));
+ S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size()));
}
static void handleLockReturnedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -970,9 +940,7 @@ static void handleLockReturnedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (Size == 0)
return;
- D->addAttr(::new (S.Context)
- LockReturnedAttr(AL.getRange(), S.Context, Args[0],
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) LockReturnedAttr(S.Context, AL, Args[0]));
}
static void handleLocksExcludedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -988,8 +956,7 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expr **StartArg = &Args[0];
D->addAttr(::new (S.Context)
- LocksExcludedAttr(AL.getRange(), S.Context, StartArg, Size,
- AL.getAttributeSpellingListIndex()));
+ LocksExcludedAttr(S.Context, AL, StartArg, Size));
}
static bool checkFunctionConditionAttr(Sema &S, Decl *D, const ParsedAttr &AL,
@@ -1026,9 +993,7 @@ static void handleEnableIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expr *Cond;
StringRef Msg;
if (checkFunctionConditionAttr(S, D, AL, Cond, Msg))
- D->addAttr(::new (S.Context)
- EnableIfAttr(AL.getRange(), S.Context, Cond, Msg,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) EnableIfAttr(S.Context, AL, Cond, Msg));
}
namespace {
@@ -1100,8 +1065,7 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (const auto *FD = dyn_cast<FunctionDecl>(D))
ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond);
D->addAttr(::new (S.Context) DiagnoseIfAttr(
- AL.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent,
- cast<NamedDecl>(D), AL.getAttributeSpellingListIndex()));
+ S.Context, AL, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D)));
}
static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1133,8 +1097,7 @@ static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context) PassObjectSizeAttr(
- AL.getRange(), S.Context, (int)Type, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) PassObjectSizeAttr(S.Context, AL, (int)Type));
}
static void handleConsumableAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1154,9 +1117,7 @@ static void handleConsumableAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- ConsumableAttr(AL.getRange(), S.Context, DefaultState,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ConsumableAttr(S.Context, AL, DefaultState));
}
static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD,
@@ -1207,8 +1168,7 @@ static void handleCallableWhenAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
D->addAttr(::new (S.Context)
- CallableWhenAttr(AL.getRange(), S.Context, States.data(),
- States.size(), AL.getAttributeSpellingListIndex()));
+ CallableWhenAttr(S.Context, AL, States.data(), States.size()));
}
static void handleParamTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1242,9 +1202,7 @@ static void handleParamTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// return;
//}
- D->addAttr(::new (S.Context)
- ParamTypestateAttr(AL.getRange(), S.Context, ParamState,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ParamTypestateAttr(S.Context, AL, ParamState));
}
static void handleReturnTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1289,9 +1247,7 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// return;
//}
- D->addAttr(::new (S.Context)
- ReturnTypestateAttr(AL.getRange(), S.Context, ReturnState,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ReturnTypestateAttr(S.Context, AL, ReturnState));
}
static void handleSetTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1313,9 +1269,7 @@ static void handleSetTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- SetTypestateAttr(AL.getRange(), S.Context, NewState,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) SetTypestateAttr(S.Context, AL, NewState));
}
static void handleTestTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1337,9 +1291,7 @@ static void handleTestTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- TestTypestateAttr(AL.getRange(), S.Context, TestState,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) TestTypestateAttr(S.Context, AL, TestState));
}
static void handleExtVectorTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1349,8 +1301,7 @@ static void handleExtVectorTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
static void handlePackedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (auto *TD = dyn_cast<TagDecl>(D))
- TD->addAttr(::new (S.Context) PackedAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ TD->addAttr(::new (S.Context) PackedAttr(S.Context, AL));
else if (auto *FD = dyn_cast<FieldDecl>(D)) {
bool BitfieldByteAligned = (!FD->getType()->isDependentType() &&
!FD->getType()->isIncompleteType() &&
@@ -1363,15 +1314,13 @@ static void handlePackedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
S.Diag(AL.getLoc(), diag::warn_attribute_ignored_for_field_of_type)
<< AL << FD->getType();
else
- FD->addAttr(::new (S.Context) PackedAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ FD->addAttr(::new (S.Context) PackedAttr(S.Context, AL));
} else {
// Report warning about changed offset in the newer compiler versions.
if (BitfieldByteAligned)
S.Diag(AL.getLoc(), diag::warn_attribute_packed_for_bitfield);
- FD->addAttr(::new (S.Context) PackedAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ FD->addAttr(::new (S.Context) PackedAttr(S.Context, AL));
}
} else
@@ -1408,9 +1357,7 @@ static void handleIBOutlet(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!checkIBOutletCommon(S, D, AL))
return;
- D->addAttr(::new (S.Context)
- IBOutletAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) IBOutletAttr(S.Context, AL));
}
static void handleIBOutletCollection(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1453,9 +1400,7 @@ static void handleIBOutletCollection(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- IBOutletCollectionAttr(AL.getRange(), S.Context, QTLoc,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) IBOutletCollectionAttr(S.Context, AL, QTLoc));
}
bool Sema::isValidPointerAttrType(QualType T, bool RefOkay) {
@@ -1538,9 +1483,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
ParamIdx *Start = NonNullArgs.data();
unsigned Size = NonNullArgs.size();
llvm::array_pod_sort(Start, Start + Size);
- D->addAttr(::new (S.Context)
- NonNullAttr(AL.getRange(), S.Context, Start, Size,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NonNullAttr(S.Context, AL, Start, Size));
}
static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D,
@@ -1560,9 +1503,7 @@ static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D,
D->getSourceRange()))
return;
- D->addAttr(::new (S.Context)
- NonNullAttr(AL.getRange(), S.Context, nullptr, 0,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NonNullAttr(S.Context, AL, nullptr, 0));
}
static void handleReturnsNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1572,9 +1513,7 @@ static void handleReturnsNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
/* isReturnValue */ true))
return;
- D->addAttr(::new (S.Context)
- ReturnsNonNullAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ReturnsNonNullAttr(S.Context, AL));
}
static void handleNoEscapeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1589,33 +1528,30 @@ static void handleNoEscapeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context) NoEscapeAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NoEscapeAttr(S.Context, AL));
}
static void handleAssumeAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expr *E = AL.getArgAsExpr(0),
*OE = AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr;
- S.AddAssumeAlignedAttr(AL.getRange(), D, E, OE,
- AL.getAttributeSpellingListIndex());
+ S.AddAssumeAlignedAttr(D, AL, E, OE);
}
static void handleAllocAlignAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- S.AddAllocAlignAttr(AL.getRange(), D, AL.getArgAsExpr(0),
- AL.getAttributeSpellingListIndex());
+ S.AddAllocAlignAttr(D, AL, AL.getArgAsExpr(0));
}
-void Sema::AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
- Expr *OE, unsigned SpellingListIndex) {
+void Sema::AddAssumeAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
+ Expr *OE) {
QualType ResultType = getFunctionOrMethodResultType(D);
SourceRange SR = getFunctionOrMethodResultSourceRange(D);
- AssumeAlignedAttr TmpAttr(AttrRange, Context, E, OE, SpellingListIndex);
- SourceLocation AttrLoc = AttrRange.getBegin();
+ AssumeAlignedAttr TmpAttr(Context, CI, E, OE);
+ SourceLocation AttrLoc = TmpAttr.getLocation();
if (!isValidPointerAttrType(ResultType, /* RefOkay */ true)) {
Diag(AttrLoc, diag::warn_attribute_return_pointers_refs_only)
- << &TmpAttr << AttrRange << SR;
+ << &TmpAttr << TmpAttr.getRange() << SR;
return;
}
@@ -1652,21 +1588,20 @@ void Sema::AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
}
}
- D->addAttr(::new (Context)
- AssumeAlignedAttr(AttrRange, Context, E, OE, SpellingListIndex));
+ D->addAttr(::new (Context) AssumeAlignedAttr(Context, CI, E, OE));
}
-void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr,
- unsigned SpellingListIndex) {
+void Sema::AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI,
+ Expr *ParamExpr) {
QualType ResultType = getFunctionOrMethodResultType(D);
- AllocAlignAttr TmpAttr(AttrRange, Context, ParamIdx(), SpellingListIndex);
- SourceLocation AttrLoc = AttrRange.getBegin();
+ AllocAlignAttr TmpAttr(Context, CI, ParamIdx());
+ SourceLocation AttrLoc = CI.getLoc();
if (!ResultType->isDependentType() &&
!isValidPointerAttrType(ResultType, /* RefOkay */ true)) {
Diag(AttrLoc, diag::warn_attribute_return_pointers_refs_only)
- << &TmpAttr << AttrRange << getFunctionOrMethodResultSourceRange(D);
+ << &TmpAttr << CI.getRange() << getFunctionOrMethodResultSourceRange(D);
return;
}
@@ -1684,8 +1619,7 @@ void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr,
return;
}
- D->addAttr(::new (Context)
- AllocAlignAttr(AttrRange, Context, Idx, SpellingListIndex));
+ D->addAttr(::new (Context) AllocAlignAttr(Context, CI, Idx));
}
/// Normalize the attribute, __foo__ becomes foo.
@@ -1716,8 +1650,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// Figure out our Kind.
OwnershipAttr::OwnershipKind K =
- OwnershipAttr(AL.getLoc(), S.Context, nullptr, nullptr, 0,
- AL.getAttributeSpellingListIndex()).getOwnKind();
+ OwnershipAttr(S.Context, AL, nullptr, nullptr, 0).getOwnKind();
// Check arguments.
switch (K) {
@@ -1799,8 +1732,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
unsigned Size = OwnershipArgs.size();
llvm::array_pod_sort(Start, Start + Size);
D->addAttr(::new (S.Context)
- OwnershipAttr(AL.getLoc(), S.Context, Module, Start, Size,
- AL.getAttributeSpellingListIndex()));
+ OwnershipAttr(S.Context, AL, Module, Start, Size));
}
static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1856,12 +1788,9 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (AL.getNumArgs() && S.checkStringLiteralArgumentAttr(AL, 0, Str))
// GCC will accept anything as the argument of weakref. Should we
// check for an existing decl?
- D->addAttr(::new (S.Context) AliasAttr(AL.getRange(), S.Context, Str,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str));
- D->addAttr(::new (S.Context)
- WeakRefAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) WeakRefAttr(S.Context, AL));
}
static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1876,8 +1805,7 @@ static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context) IFuncAttr(AL.getRange(), S.Context, Str,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) IFuncAttr(S.Context, AL, Str));
}
static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1918,8 +1846,7 @@ static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
ND->markUsed(S.Context);
}
- D->addAttr(::new (S.Context) AliasAttr(AL.getRange(), S.Context, Str,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str));
}
static void handleTLSModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1936,16 +1863,13 @@ static void handleTLSModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- TLSModelAttr(AL.getRange(), S.Context, Model,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) TLSModelAttr(S.Context, AL, Model));
}
static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
QualType ResultType = getFunctionOrMethodResultType(D);
if (ResultType->isAnyPointerType() || ResultType->isBlockPointerType()) {
- D->addAttr(::new (S.Context) RestrictAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) RestrictAttr(S.Context, AL));
return;
}
@@ -1996,13 +1920,11 @@ static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
FD->setIsMultiVersion(true);
if (AL.getKind() == ParsedAttr::AT_CPUSpecific)
- D->addAttr(::new (S.Context) CPUSpecificAttr(
- AL.getRange(), S.Context, CPUs.data(), CPUs.size(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ CPUSpecificAttr(S.Context, AL, CPUs.data(), CPUs.size()));
else
- D->addAttr(::new (S.Context) CPUDispatchAttr(
- AL.getRange(), S.Context, CPUs.data(), CPUs.size(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ CPUDispatchAttr(S.Context, AL, CPUs.data(), CPUs.size()));
}
static void handleCommonAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2031,8 +1953,7 @@ static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
- D->addAttr(::new (S.Context) NakedAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NakedAttr(S.Context, AL));
}
static void handleNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) {
@@ -2044,8 +1965,7 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) {
return;
}
- D->addAttr(::new (S.Context) NoReturnAttr(
- Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NoReturnAttr(S.Context, Attrs));
}
static void handleNoCfCheckAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) {
@@ -2091,9 +2011,7 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
- D->addAttr(::new (S.Context)
- AnalyzerNoReturnAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(S.Context, AL));
}
// PS3 PPU-specific.
@@ -2148,8 +2066,7 @@ static void handleVecReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
count++;
}
- D->addAttr(::new (S.Context) VecReturnAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) VecReturnAttr(S.Context, AL));
}
static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D,
@@ -2164,9 +2081,7 @@ static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D,
}
}
- D->addAttr(::new (S.Context) CarriesDependencyAttr(
- AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) CarriesDependencyAttr(S.Context, AL));
}
static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2177,8 +2092,7 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!S.getLangOpts().CPlusPlus17 && IsCXX17Attr)
S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL;
- D->addAttr(::new (S.Context) UnusedAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL));
}
static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2187,9 +2101,7 @@ static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority))
return;
- D->addAttr(::new (S.Context)
- ConstructorAttr(AL.getRange(), S.Context, priority,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority));
}
static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2198,9 +2110,7 @@ static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority))
return;
- D->addAttr(::new (S.Context)
- DestructorAttr(AL.getRange(), S.Context, priority,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority));
}
template <typename AttrTy>
@@ -2210,8 +2120,7 @@ static void handleAttrWithMessage(Sema &S, Decl *D, const ParsedAttr &AL) {
if (AL.getNumArgs() == 1 && !S.checkStringLiteralArgumentAttr(AL, 0, Str))
return;
- D->addAttr(::new (S.Context) AttrTy(AL.getRange(), S.Context, Str,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AttrTy(S.Context, AL, Str));
}
static void handleObjCSuppresProtocolAttr(Sema &S, Decl *D,
@@ -2222,9 +2131,7 @@ static void handleObjCSuppresProtocolAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context)
- ObjCExplicitProtocolImplAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCExplicitProtocolImplAttr(S.Context, AL));
}
static bool checkAvailabilityAttr(Sema &S, SourceRange Range,
@@ -2285,10 +2192,11 @@ static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y,
}
AvailabilityAttr *Sema::mergeAvailabilityAttr(
- NamedDecl *D, SourceRange Range, IdentifierInfo *Platform, bool Implicit,
- VersionTuple Introduced, VersionTuple Deprecated, VersionTuple Obsoleted,
- bool IsUnavailable, StringRef Message, bool IsStrict, StringRef Replacement,
- AvailabilityMergeKind AMK, int Priority, unsigned AttrSpellingListIndex) {
+ NamedDecl *D, const AttributeCommonInfo &CI, IdentifierInfo *Platform,
+ bool Implicit, VersionTuple Introduced, VersionTuple Deprecated,
+ VersionTuple Obsoleted, bool IsUnavailable, StringRef Message,
+ bool IsStrict, StringRef Replacement, AvailabilityMergeKind AMK,
+ int Priority) {
VersionTuple MergedIntroduced = Introduced;
VersionTuple MergedDeprecated = Deprecated;
VersionTuple MergedObsoleted = Obsoleted;
@@ -2379,12 +2287,12 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(
<< (AMK == AMK_Override);
}
if (AMK == AMK_Override)
- Diag(Range.getBegin(), diag::note_overridden_method);
+ Diag(CI.getLoc(), diag::note_overridden_method);
else
- Diag(Range.getBegin(), diag::note_protocol_method);
+ Diag(CI.getLoc(), diag::note_protocol_method);
} else {
Diag(OldAA->getLocation(), diag::warn_mismatched_availability);
- Diag(Range.getBegin(), diag::note_previous_attribute);
+ Diag(CI.getLoc(), diag::note_previous_attribute);
}
Attrs.erase(Attrs.begin() + i);
@@ -2426,13 +2334,12 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(
// Only create a new attribute if !OverrideOrImpl, but we want to do
// the checking.
- if (!checkAvailabilityAttr(*this, Range, Platform, MergedIntroduced,
+ if (!checkAvailabilityAttr(*this, CI.getRange(), Platform, MergedIntroduced,
MergedDeprecated, MergedObsoleted) &&
!OverrideOrImpl) {
- auto *Avail = ::new (Context)
- AvailabilityAttr(Range, Context, Platform, Introduced, Deprecated,
- Obsoleted, IsUnavailable, Message, IsStrict,
- Replacement, Priority, AttrSpellingListIndex);
+ auto *Avail = ::new (Context) AvailabilityAttr(
+ Context, CI, Platform, Introduced, Deprecated, Obsoleted, IsUnavailable,
+ Message, IsStrict, Replacement, Priority);
Avail->setImplicit(Implicit);
return Avail;
}
@@ -2443,7 +2350,6 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!checkAttributeNumArgs(S, AL, 1))
return;
IdentifierLoc *Platform = AL.getArgAsIdent(0);
- unsigned Index = AL.getAttributeSpellingListIndex();
IdentifierInfo *II = Platform->Ident;
if (AvailabilityAttr::getPrettyPlatformName(II->getName()).empty())
@@ -2479,9 +2385,9 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
? Sema::AP_PragmaClangAttribute
: Sema::AP_Explicit;
AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
- ND, AL.getRange(), II, false /*Implicit*/, Introduced.Version,
- Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, IsStrict,
- Replacement, Sema::AMK_None, PriorityModifier, Index);
+ ND, AL, II, false /*Implicit*/, Introduced.Version, Deprecated.Version,
+ Obsoleted.Version, IsUnavailable, Str, IsStrict, Replacement,
+ Sema::AMK_None, PriorityModifier);
if (NewAttr)
D->addAttr(NewAttr);
@@ -2519,10 +2425,10 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version);
AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
- ND, AL.getRange(), NewII, true /*Implicit*/, NewIntroduced,
- NewDeprecated, NewObsoleted, IsUnavailable, Str, IsStrict,
- Replacement, Sema::AMK_None,
- PriorityModifier + Sema::AP_InferredFromOtherPlatform, Index);
+ ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated,
+ NewObsoleted, IsUnavailable, Str, IsStrict, Replacement,
+ Sema::AMK_None,
+ PriorityModifier + Sema::AP_InferredFromOtherPlatform);
if (NewAttr)
D->addAttr(NewAttr);
}
@@ -2537,10 +2443,10 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (NewII) {
AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
- ND, AL.getRange(), NewII, true /*Implicit*/, Introduced.Version,
+ ND, AL, NewII, true /*Implicit*/, Introduced.Version,
Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, IsStrict,
Replacement, Sema::AMK_None,
- PriorityModifier + Sema::AP_InferredFromOtherPlatform, Index);
+ PriorityModifier + Sema::AP_InferredFromOtherPlatform);
if (NewAttr)
D->addAttr(NewAttr);
}
@@ -2563,38 +2469,34 @@ static void handleExternalSourceSymbolAttr(Sema &S, Decl *D,
bool IsGeneratedDeclaration = AL.getArgAsIdent(2) != nullptr;
D->addAttr(::new (S.Context) ExternalSourceSymbolAttr(
- AL.getRange(), S.Context, Language, DefinedIn, IsGeneratedDeclaration,
- AL.getAttributeSpellingListIndex()));
+ S.Context, AL, Language, DefinedIn, IsGeneratedDeclaration));
}
template <class T>
-static T *mergeVisibilityAttr(Sema &S, Decl *D, SourceRange range,
- typename T::VisibilityType value,
- unsigned attrSpellingListIndex) {
+static T *mergeVisibilityAttr(Sema &S, Decl *D, const AttributeCommonInfo &CI,
+ typename T::VisibilityType value) {
T *existingAttr = D->getAttr<T>();
if (existingAttr) {
typename T::VisibilityType existingValue = existingAttr->getVisibility();
if (existingValue == value)
return nullptr;
S.Diag(existingAttr->getLocation(), diag::err_mismatched_visibility);
- S.Diag(range.getBegin(), diag::note_previous_attribute);
+ S.Diag(CI.getLoc(), diag::note_previous_attribute);
D->dropAttr<T>();
}
- return ::new (S.Context) T(range, S.Context, value, attrSpellingListIndex);
+ return ::new (S.Context) T(S.Context, CI, value);
}
-VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D, SourceRange Range,
- VisibilityAttr::VisibilityType Vis,
- unsigned AttrSpellingListIndex) {
- return ::mergeVisibilityAttr<VisibilityAttr>(*this, D, Range, Vis,
- AttrSpellingListIndex);
+VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D,
+ const AttributeCommonInfo &CI,
+ VisibilityAttr::VisibilityType Vis) {
+ return ::mergeVisibilityAttr<VisibilityAttr>(*this, D, CI, Vis);
}
-TypeVisibilityAttr *Sema::mergeTypeVisibilityAttr(Decl *D, SourceRange Range,
- TypeVisibilityAttr::VisibilityType Vis,
- unsigned AttrSpellingListIndex) {
- return ::mergeVisibilityAttr<TypeVisibilityAttr>(*this, D, Range, Vis,
- AttrSpellingListIndex);
+TypeVisibilityAttr *
+Sema::mergeTypeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI,
+ TypeVisibilityAttr::VisibilityType Vis) {
+ return ::mergeVisibilityAttr<TypeVisibilityAttr>(*this, D, CI, Vis);
}
static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL,
@@ -2636,14 +2538,12 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL,
type = VisibilityAttr::Default;
}
- unsigned Index = AL.getAttributeSpellingListIndex();
Attr *newAttr;
if (isTypeVisibility) {
- newAttr = S.mergeTypeVisibilityAttr(D, AL.getRange(),
- (TypeVisibilityAttr::VisibilityType) type,
- Index);
+ newAttr = S.mergeTypeVisibilityAttr(
+ D, AL, (TypeVisibilityAttr::VisibilityType)type);
} else {
- newAttr = S.mergeVisibilityAttr(D, AL.getRange(), type, Index);
+ newAttr = S.mergeVisibilityAttr(D, AL, type);
}
if (newAttr)
D->addAttr(newAttr);
@@ -2672,8 +2572,7 @@ static void handleObjCMethodFamilyAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(new (S.Context) ObjCMethodFamilyAttr(
- AL.getRange(), S.Context, F, AL.getAttributeSpellingListIndex()));
+ D->addAttr(new (S.Context) ObjCMethodFamilyAttr(S.Context, AL, F));
}
static void handleObjCNSObject(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2700,9 +2599,7 @@ static void handleObjCNSObject(Sema &S, Decl *D, const ParsedAttr &AL) {
// case.
S.Diag(D->getLocation(), diag::warn_nsobject_attribute);
}
- D->addAttr(::new (S.Context)
- ObjCNSObjectAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCNSObjectAttr(S.Context, AL));
}
static void handleObjCIndependentClass(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2716,9 +2613,7 @@ static void handleObjCIndependentClass(Sema &S, Decl *D, const ParsedAttr &AL) {
S.Diag(D->getLocation(), diag::warn_independentclass_attribute);
return;
}
- D->addAttr(::new (S.Context)
- ObjCIndependentClassAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCIndependentClassAttr(S.Context, AL));
}
static void handleBlocksAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2735,9 +2630,7 @@ static void handleBlocksAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- BlocksAttr(AL.getRange(), S.Context, type,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) BlocksAttr(S.Context, AL, type));
}
static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2808,7 +2701,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
const FunctionType *FT = Ty->isFunctionPointerType()
? D->getFunctionType()
- : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
+ : Ty->castAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
if (!cast<FunctionProtoType>(FT)->isVariadic()) {
int m = Ty->isFunctionPointerType() ? 0 : 1;
S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m;
@@ -2824,14 +2717,13 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
<< AL << ExpectedFunctionMethodOrBlock;
return;
}
- D->addAttr(::new (S.Context)
- SentinelAttr(AL.getRange(), S.Context, sentinel, nullPos,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) SentinelAttr(S.Context, AL, sentinel, nullPos));
}
static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) {
if (D->getFunctionType() &&
- D->getFunctionType()->getReturnType()->isVoidType()) {
+ D->getFunctionType()->getReturnType()->isVoidType() &&
+ !isa<CXXConstructorDecl>(D)) {
S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) << AL << 0;
return;
}
@@ -2841,15 +2733,29 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- // If this is spelled as the standard C++17 attribute, but not in C++17, warn
- // about using it as an extension.
- if (!S.getLangOpts().CPlusPlus17 && AL.isCXX11Attribute() &&
- !AL.getScopeName())
- S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL;
+ StringRef Str;
+ if ((AL.isCXX11Attribute() || AL.isC2xAttribute()) && !AL.getScopeName()) {
+ // If this is spelled as the standard C++17 attribute, but not in C++17,
+ // warn about using it as an extension. If there are attribute arguments,
+ // then claim it's a C++2a extension instead.
+ // FIXME: If WG14 does not seem likely to adopt the same feature, add an
+ // extension warning for C2x mode.
+ const LangOptions &LO = S.getLangOpts();
+ if (AL.getNumArgs() == 1) {
+ if (LO.CPlusPlus && !LO.CPlusPlus2a)
+ S.Diag(AL.getLoc(), diag::ext_cxx2a_attr) << AL;
+
+ // Since this this is spelled [[nodiscard]], get the optional string
+ // literal. If in C++ mode, but not in C++2a mode, diagnose as an
+ // extension.
+ // FIXME: C2x should support this feature as well, even as an extension.
+ if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, nullptr))
+ return;
+ } else if (LO.CPlusPlus && !LO.CPlusPlus17)
+ S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL;
+ }
- D->addAttr(::new (S.Context)
- WarnUnusedResultAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) WarnUnusedResultAttr(S.Context, AL, Str));
}
static void handleWeakImportAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2870,9 +2776,7 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- WeakImportAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) WeakImportAttr(S.Context, AL));
}
// Handles reqd_work_group_size and work_group_size_hint.
@@ -2897,9 +2801,8 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) {
Existing->getZDim() == WGSize[2]))
S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
- D->addAttr(::new (S.Context) WorkGroupAttr(AL.getRange(), S.Context,
- WGSize[0], WGSize[1], WGSize[2],
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ WorkGroupAttr(S.Context, AL, WGSize[0], WGSize[1], WGSize[2]));
}
// Handles intel_reqd_sub_group_size.
@@ -2919,9 +2822,8 @@ static void handleSubGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) {
if (Existing && Existing->getSubGroupSize() != SGSize)
S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
- D->addAttr(::new (S.Context) OpenCLIntelReqdSubGroupSizeAttr(
- AL.getRange(), S.Context, SGSize,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ OpenCLIntelReqdSubGroupSizeAttr(S.Context, AL, SGSize));
}
static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2937,8 +2839,7 @@ static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!ParmType->isExtVectorType() && !ParmType->isFloatingType() &&
(ParmType->isBooleanType() ||
!ParmType->isIntegralType(S.getASTContext()))) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_vec_type_hint)
- << ParmType;
+ S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument) << 3 << AL;
return;
}
@@ -2949,18 +2850,15 @@ static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
- D->addAttr(::new (S.Context) VecTypeHintAttr(AL.getLoc(), S.Context,
- ParmTSI,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) VecTypeHintAttr(S.Context, AL, ParmTSI));
}
-SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
- StringRef Name,
- unsigned AttrSpellingListIndex) {
+SectionAttr *Sema::mergeSectionAttr(Decl *D, const AttributeCommonInfo &CI,
+ StringRef Name) {
// Explicit or partial specializations do not inherit
// the section attribute from the primary template.
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- if (AttrSpellingListIndex == SectionAttr::Declspec_allocate &&
+ if (CI.getAttributeSpellingListIndex() == SectionAttr::Declspec_allocate &&
FD->isFunctionTemplateSpecialization())
return nullptr;
}
@@ -2969,11 +2867,10 @@ SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
return nullptr;
Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section)
<< 1 /*section*/;
- Diag(Range.getBegin(), diag::note_previous_attribute);
+ Diag(CI.getLoc(), diag::note_previous_attribute);
return nullptr;
}
- return ::new (Context) SectionAttr(Range, Context, Name,
- AttrSpellingListIndex);
+ return ::new (Context) SectionAttr(Context, CI, Name);
}
bool Sema::checkSectionName(SourceLocation LiteralLoc, StringRef SecName) {
@@ -3005,8 +2902,7 @@ static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- unsigned Index = AL.getAttributeSpellingListIndex();
- SectionAttr *NewAttr = S.mergeSectionAttr(D, AL.getRange(), Str, Index);
+ SectionAttr *NewAttr = S.mergeSectionAttr(D, AL, Str);
if (NewAttr)
D->addAttr(NewAttr);
}
@@ -3026,9 +2922,8 @@ static bool checkCodeSegName(Sema &S, SourceLocation LiteralLoc,
return true;
}
-CodeSegAttr *Sema::mergeCodeSegAttr(Decl *D, SourceRange Range,
- StringRef Name,
- unsigned AttrSpellingListIndex) {
+CodeSegAttr *Sema::mergeCodeSegAttr(Decl *D, const AttributeCommonInfo &CI,
+ StringRef Name) {
// Explicit or partial specializations do not inherit
// the code_seg attribute from the primary template.
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
@@ -3040,11 +2935,10 @@ CodeSegAttr *Sema::mergeCodeSegAttr(Decl *D, SourceRange Range,
return nullptr;
Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section)
<< 0 /*codeseg*/;
- Diag(Range.getBegin(), diag::note_previous_attribute);
+ Diag(CI.getLoc(), diag::note_previous_attribute);
return nullptr;
}
- return ::new (Context) CodeSegAttr(Range, Context, Name,
- AttrSpellingListIndex);
+ return ::new (Context) CodeSegAttr(Context, CI, Name);
}
static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -3064,8 +2958,7 @@ static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
D->dropAttr<CodeSegAttr>();
}
- if (CodeSegAttr *CSA = S.mergeCodeSegAttr(D, AL.getRange(), Str,
- AL.getAttributeSpellingListIndex()))
+ if (CodeSegAttr *CSA = S.mergeCodeSegAttr(D, AL, Str))
D->addAttr(CSA);
}
@@ -3107,9 +3000,7 @@ static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
S.checkTargetAttr(LiteralLoc, Str))
return;
- unsigned Index = AL.getAttributeSpellingListIndex();
- TargetAttr *NewAttr =
- ::new (S.Context) TargetAttr(AL.getRange(), S.Context, Str, Index);
+ TargetAttr *NewAttr = ::new (S.Context) TargetAttr(S.Context, AL, Str);
D->addAttr(NewAttr);
}
@@ -3127,9 +3018,7 @@ static void handleMinVectorWidthAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- MinVectorWidthAttr(AL.getRange(), S.Context, VecWidth,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) MinVectorWidthAttr(S.Context, AL, VecWidth));
}
static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -3184,9 +3073,7 @@ static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- CleanupAttr(AL.getRange(), S.Context, FD,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) CleanupAttr(S.Context, AL, FD));
}
static void handleEnumExtensibilityAttr(Sema &S, Decl *D,
@@ -3205,9 +3092,8 @@ static void handleEnumExtensibilityAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) EnumExtensibilityAttr(
- AL.getRange(), S.Context, ExtensibilityKind,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ EnumExtensibilityAttr(S.Context, AL, ExtensibilityKind));
}
/// Handle __attribute__((format_arg((idx)))) attribute based on
@@ -3225,7 +3111,7 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (NotNSStringTy &&
!isCFStringType(Ty, S.Context) &&
(!Ty->isPointerType() ||
- !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) {
+ !Ty->castAs<PointerType>()->getPointeeType()->isCharType())) {
S.Diag(AL.getLoc(), diag::err_format_attribute_not)
<< "a string type" << IdxExpr->getSourceRange()
<< getFunctionOrMethodParamRange(D, 0);
@@ -3235,15 +3121,14 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!isNSStringType(Ty, S.Context) &&
!isCFStringType(Ty, S.Context) &&
(!Ty->isPointerType() ||
- !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) {
+ !Ty->castAs<PointerType>()->getPointeeType()->isCharType())) {
S.Diag(AL.getLoc(), diag::err_format_attribute_result_not)
<< (NotNSStringTy ? "string type" : "NSString")
<< IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0);
return;
}
- D->addAttr(::new (S.Context) FormatArgAttr(
- AL.getRange(), S.Context, Idx, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) FormatArgAttr(S.Context, AL, Idx));
}
enum FormatAttrKind {
@@ -3311,15 +3196,12 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
AL.setInvalid();
return;
}
- D->addAttr(::new (S.Context)
- InitPriorityAttr(AL.getRange(), S.Context, prioritynum,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) InitPriorityAttr(S.Context, AL, prioritynum));
}
-FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range,
+FormatAttr *Sema::mergeFormatAttr(Decl *D, const AttributeCommonInfo &CI,
IdentifierInfo *Format, int FormatIdx,
- int FirstArg,
- unsigned AttrSpellingListIndex) {
+ int FirstArg) {
// Check whether we already have an equivalent format attribute.
for (auto *F : D->specific_attrs<FormatAttr>()) {
if (F->getType() == Format &&
@@ -3328,13 +3210,12 @@ FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range,
// If we don't have a valid location for this attribute, adopt the
// location.
if (F->getLocation().isInvalid())
- F->setRange(Range);
+ F->setRange(CI.getRange());
return nullptr;
}
}
- return ::new (Context) FormatAttr(Range, Context, Format, FormatIdx,
- FirstArg, AttrSpellingListIndex);
+ return ::new (Context) FormatAttr(Context, CI, Format, FormatIdx, FirstArg);
}
/// Handle __attribute__((format(type,idx,firstarg))) attributes based on
@@ -3416,7 +3297,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
} else if (!Ty->isPointerType() ||
- !Ty->getAs<PointerType>()->getPointeeType()->isCharType()) {
+ !Ty->castAs<PointerType>()->getPointeeType()->isCharType()) {
S.Diag(AL.getLoc(), diag::err_format_attribute_not)
<< "a string type" << IdxExpr->getSourceRange()
<< getFunctionOrMethodParamRange(D, ArgIdx);
@@ -3454,9 +3335,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- FormatAttr *NewAttr = S.mergeFormatAttr(D, AL.getRange(), II,
- Idx, FirstArg,
- AL.getAttributeSpellingListIndex());
+ FormatAttr *NewAttr = S.mergeFormatAttr(D, AL, II, Idx, FirstArg);
if (NewAttr)
D->addAttr(NewAttr);
}
@@ -3597,8 +3476,7 @@ static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
D->addAttr(::new (S.Context) CallbackAttr(
- AL.getRange(), S.Context, EncodingIndices.data(), EncodingIndices.size(),
- AL.getAttributeSpellingListIndex()));
+ S.Context, AL, EncodingIndices.data(), EncodingIndices.size()));
}
static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -3669,9 +3547,7 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
- RD->addAttr(::new (S.Context)
- TransparentUnionAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ RD->addAttr(::new (S.Context) TransparentUnionAttr(S.Context, AL));
}
static void handleAnnotateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -3687,20 +3563,16 @@ static void handleAnnotateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- AnnotateAttr(AL.getRange(), S.Context, Str,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AnnotateAttr(S.Context, AL, Str));
}
static void handleAlignValueAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- S.AddAlignValueAttr(AL.getRange(), D, AL.getArgAsExpr(0),
- AL.getAttributeSpellingListIndex());
+ S.AddAlignValueAttr(D, AL, AL.getArgAsExpr(0));
}
-void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E,
- unsigned SpellingListIndex) {
- AlignValueAttr TmpAttr(AttrRange, Context, E, SpellingListIndex);
- SourceLocation AttrLoc = AttrRange.getBegin();
+void Sema::AddAlignValueAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E) {
+ AlignValueAttr TmpAttr(Context, CI, E);
+ SourceLocation AttrLoc = CI.getLoc();
QualType T;
if (const auto *TD = dyn_cast<TypedefNameDecl>(D))
@@ -3732,14 +3604,12 @@ void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E,
return;
}
- D->addAttr(::new (Context)
- AlignValueAttr(AttrRange, Context, ICE.get(),
- SpellingListIndex));
+ D->addAttr(::new (Context) AlignValueAttr(Context, CI, ICE.get()));
return;
}
// Save dependent expressions in the AST to be instantiated.
- D->addAttr(::new (Context) AlignValueAttr(TmpAttr));
+ D->addAttr(::new (Context) AlignValueAttr(Context, CI, E));
}
static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -3750,8 +3620,7 @@ static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
if (AL.getNumArgs() == 0) {
- D->addAttr(::new (S.Context) AlignedAttr(AL.getRange(), S.Context,
- true, nullptr, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AlignedAttr(S.Context, AL, true, nullptr));
return;
}
@@ -3765,14 +3634,13 @@ static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!AL.isPackExpansion() && S.DiagnoseUnexpandedParameterPack(E))
return;
- S.AddAlignedAttr(AL.getRange(), D, E, AL.getAttributeSpellingListIndex(),
- AL.isPackExpansion());
+ S.AddAlignedAttr(D, AL, E, AL.isPackExpansion());
}
-void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
- unsigned SpellingListIndex, bool IsPackExpansion) {
- AlignedAttr TmpAttr(AttrRange, Context, true, E, SpellingListIndex);
- SourceLocation AttrLoc = AttrRange.getBegin();
+void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
+ bool IsPackExpansion) {
+ AlignedAttr TmpAttr(Context, CI, true, E);
+ SourceLocation AttrLoc = CI.getLoc();
// C++11 alignas(...) and C11 _Alignas(...) have additional requirements.
if (TmpAttr.isAlignas()) {
@@ -3824,7 +3692,7 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
}
// Save dependent expressions in the AST to be instantiated.
- AlignedAttr *AA = ::new (Context) AlignedAttr(TmpAttr);
+ AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, true, E);
AA->setPackExpansion(IsPackExpansion);
D->addAttr(AA);
return;
@@ -3877,18 +3745,16 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
}
}
- AlignedAttr *AA = ::new (Context) AlignedAttr(AttrRange, Context, true,
- ICE.get(), SpellingListIndex);
+ AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, true, ICE.get());
AA->setPackExpansion(IsPackExpansion);
D->addAttr(AA);
}
-void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS,
- unsigned SpellingListIndex, bool IsPackExpansion) {
+void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI,
+ TypeSourceInfo *TS, bool IsPackExpansion) {
// FIXME: Cache the number on the AL object if non-dependent?
// FIXME: Perform checking of type validity
- AlignedAttr *AA = ::new (Context) AlignedAttr(AttrRange, Context, false, TS,
- SpellingListIndex);
+ AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, false, TS);
AA->setPackExpansion(IsPackExpansion);
D->addAttr(AA);
}
@@ -4032,14 +3898,14 @@ static void handleModeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
IdentifierInfo *Name = AL.getArgAsIdent(0)->Ident;
- S.AddModeAttr(AL.getRange(), D, Name, AL.getAttributeSpellingListIndex());
+ S.AddModeAttr(D, AL, Name);
}
-void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name,
- unsigned SpellingListIndex, bool InInstantiation) {
+void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI,
+ IdentifierInfo *Name, bool InInstantiation) {
StringRef Str = Name->getName();
normalizeName(Str);
- SourceLocation AttrLoc = AttrRange.getBegin();
+ SourceLocation AttrLoc = CI.getLoc();
unsigned DestWidth = 0;
bool IntegerMode = true;
@@ -4090,8 +3956,7 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name,
OldTy = cast<ValueDecl>(D)->getType();
if (OldTy->isDependentType()) {
- D->addAttr(::new (Context)
- ModeAttr(AttrRange, Context, Name, SpellingListIndex));
+ D->addAttr(::new (Context) ModeAttr(Context, CI, Name));
return;
}
@@ -4106,7 +3971,7 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name,
// type, 'enum { A } __attribute__((mode(V4SI)))' is rejected.
if ((isa<EnumDecl>(D) || OldElemTy->getAs<EnumType>()) &&
VectorSize.getBoolValue()) {
- Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << AttrRange;
+ Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << CI.getRange();
return;
}
bool IntegralOrAnyEnumType =
@@ -4173,21 +4038,18 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name,
else
cast<ValueDecl>(D)->setType(NewTy);
- D->addAttr(::new (Context)
- ModeAttr(AttrRange, Context, Name, SpellingListIndex));
+ D->addAttr(::new (Context) ModeAttr(Context, CI, Name));
}
static void handleNoDebugAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- D->addAttr(::new (S.Context)
- NoDebugAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NoDebugAttr(S.Context, AL));
}
-AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D, SourceRange Range,
- IdentifierInfo *Ident,
- unsigned AttrSpellingListIndex) {
+AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D,
+ const AttributeCommonInfo &CI,
+ const IdentifierInfo *Ident) {
if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) {
- Diag(Range.getBegin(), diag::warn_attribute_ignored) << Ident;
+ Diag(CI.getLoc(), diag::warn_attribute_ignored) << Ident;
Diag(Optnone->getLocation(), diag::note_conflicting_attribute);
return nullptr;
}
@@ -4195,24 +4057,21 @@ AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D, SourceRange Range,
if (D->hasAttr<AlwaysInlineAttr>())
return nullptr;
- return ::new (Context) AlwaysInlineAttr(Range, Context,
- AttrSpellingListIndex);
+ return ::new (Context) AlwaysInlineAttr(Context, CI);
}
CommonAttr *Sema::mergeCommonAttr(Decl *D, const ParsedAttr &AL) {
if (checkAttrMutualExclusion<InternalLinkageAttr>(*this, D, AL))
return nullptr;
- return ::new (Context)
- CommonAttr(AL.getRange(), Context, AL.getAttributeSpellingListIndex());
+ return ::new (Context) CommonAttr(Context, AL);
}
CommonAttr *Sema::mergeCommonAttr(Decl *D, const CommonAttr &AL) {
if (checkAttrMutualExclusion<InternalLinkageAttr>(*this, D, AL))
return nullptr;
- return ::new (Context)
- CommonAttr(AL.getRange(), Context, AL.getSpellingListIndex());
+ return ::new (Context) CommonAttr(Context, AL);
}
InternalLinkageAttr *Sema::mergeInternalLinkageAttr(Decl *D,
@@ -4236,8 +4095,7 @@ InternalLinkageAttr *Sema::mergeInternalLinkageAttr(Decl *D,
if (checkAttrMutualExclusion<CommonAttr>(*this, D, AL))
return nullptr;
- return ::new (Context) InternalLinkageAttr(
- AL.getRange(), Context, AL.getAttributeSpellingListIndex());
+ return ::new (Context) InternalLinkageAttr(Context, AL);
}
InternalLinkageAttr *
Sema::mergeInternalLinkageAttr(Decl *D, const InternalLinkageAttr &AL) {
@@ -4260,14 +4118,12 @@ Sema::mergeInternalLinkageAttr(Decl *D, const InternalLinkageAttr &AL) {
if (checkAttrMutualExclusion<CommonAttr>(*this, D, AL))
return nullptr;
- return ::new (Context)
- InternalLinkageAttr(AL.getRange(), Context, AL.getSpellingListIndex());
+ return ::new (Context) InternalLinkageAttr(Context, AL);
}
-MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range,
- unsigned AttrSpellingListIndex) {
+MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, const AttributeCommonInfo &CI) {
if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) {
- Diag(Range.getBegin(), diag::warn_attribute_ignored) << "'minsize'";
+ Diag(CI.getLoc(), diag::warn_attribute_ignored) << "'minsize'";
Diag(Optnone->getLocation(), diag::note_conflicting_attribute);
return nullptr;
}
@@ -4275,7 +4131,7 @@ MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range,
if (D->hasAttr<MinSizeAttr>())
return nullptr;
- return ::new (Context) MinSizeAttr(Range, Context, AttrSpellingListIndex);
+ return ::new (Context) MinSizeAttr(Context, CI);
}
NoSpeculativeLoadHardeningAttr *Sema::mergeNoSpeculativeLoadHardeningAttr(
@@ -4283,28 +4139,26 @@ NoSpeculativeLoadHardeningAttr *Sema::mergeNoSpeculativeLoadHardeningAttr(
if (checkAttrMutualExclusion<SpeculativeLoadHardeningAttr>(*this, D, AL))
return nullptr;
- return ::new (Context) NoSpeculativeLoadHardeningAttr(
- AL.getRange(), Context, AL.getSpellingListIndex());
+ return ::new (Context) NoSpeculativeLoadHardeningAttr(Context, AL);
}
-OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
- unsigned AttrSpellingListIndex) {
+OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D,
+ const AttributeCommonInfo &CI) {
if (AlwaysInlineAttr *Inline = D->getAttr<AlwaysInlineAttr>()) {
Diag(Inline->getLocation(), diag::warn_attribute_ignored) << Inline;
- Diag(Range.getBegin(), diag::note_conflicting_attribute);
+ Diag(CI.getLoc(), diag::note_conflicting_attribute);
D->dropAttr<AlwaysInlineAttr>();
}
if (MinSizeAttr *MinSize = D->getAttr<MinSizeAttr>()) {
Diag(MinSize->getLocation(), diag::warn_attribute_ignored) << MinSize;
- Diag(Range.getBegin(), diag::note_conflicting_attribute);
+ Diag(CI.getLoc(), diag::note_conflicting_attribute);
D->dropAttr<MinSizeAttr>();
}
if (D->hasAttr<OptimizeNoneAttr>())
return nullptr;
- return ::new (Context) OptimizeNoneAttr(Range, Context,
- AttrSpellingListIndex);
+ return ::new (Context) OptimizeNoneAttr(Context, CI);
}
SpeculativeLoadHardeningAttr *Sema::mergeSpeculativeLoadHardeningAttr(
@@ -4312,29 +4166,25 @@ SpeculativeLoadHardeningAttr *Sema::mergeSpeculativeLoadHardeningAttr(
if (checkAttrMutualExclusion<NoSpeculativeLoadHardeningAttr>(*this, D, AL))
return nullptr;
- return ::new (Context) SpeculativeLoadHardeningAttr(
- AL.getRange(), Context, AL.getSpellingListIndex());
+ return ::new (Context) SpeculativeLoadHardeningAttr(Context, AL);
}
static void handleAlwaysInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, AL))
return;
- if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr(
- D, AL.getRange(), AL.getName(),
- AL.getAttributeSpellingListIndex()))
+ if (AlwaysInlineAttr *Inline =
+ S.mergeAlwaysInlineAttr(D, AL, AL.getAttrName()))
D->addAttr(Inline);
}
static void handleMinSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (MinSizeAttr *MinSize = S.mergeMinSizeAttr(
- D, AL.getRange(), AL.getAttributeSpellingListIndex()))
+ if (MinSizeAttr *MinSize = S.mergeMinSizeAttr(D, AL))
D->addAttr(MinSize);
}
static void handleOptimizeNoneAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (OptimizeNoneAttr *Optnone = S.mergeOptimizeNoneAttr(
- D, AL.getRange(), AL.getAttributeSpellingListIndex()))
+ if (OptimizeNoneAttr *Optnone = S.mergeOptimizeNoneAttr(D, AL))
D->addAttr(Optnone);
}
@@ -4346,8 +4196,7 @@ static void handleConstantAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
S.Diag(AL.getLoc(), diag::err_cuda_nonglobal_constant);
return;
}
- D->addAttr(::new (S.Context) CUDAConstantAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) CUDAConstantAttr(S.Context, AL));
}
static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -4365,8 +4214,7 @@ static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
S.CUDADiagIfHostCode(AL.getLoc(), diag::err_cuda_host_shared)
<< S.CurrentCUDATarget())
return;
- D->addAttr(::new (S.Context) CUDASharedAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) CUDASharedAttr(S.Context, AL));
}
static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -4375,7 +4223,9 @@ static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
const auto *FD = cast<FunctionDecl>(D);
- if (!FD->getReturnType()->isVoidType()) {
+ if (!FD->getReturnType()->isVoidType() &&
+ !FD->getReturnType()->getAs<AutoType>() &&
+ !FD->getReturnType()->isInstantiationDependentType()) {
SourceRange RTRange = FD->getReturnTypeSourceRange();
S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return)
<< FD->getType()
@@ -4395,9 +4245,7 @@ static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (FD->isInlineSpecified() && !S.getLangOpts().CUDAIsDevice)
S.Diag(FD->getBeginLoc(), diag::warn_kern_is_inline) << FD;
- D->addAttr(::new (S.Context)
- CUDAGlobalAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) CUDAGlobalAttr(S.Context, AL));
}
static void handleGNUInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -4407,9 +4255,10 @@ static void handleGNUInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- GNUInlineAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ if (S.LangOpts.CPlusPlus && Fn->getStorageClass() != SC_Extern)
+ S.Diag(AL.getLoc(), diag::warn_gnu_inline_cplusplus_without_extern);
+
+ D->addAttr(::new (S.Context) GNUInlineAttr(S.Context, AL));
}
static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -4429,53 +4278,34 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
switch (AL.getKind()) {
case ParsedAttr::AT_FastCall:
- D->addAttr(::new (S.Context)
- FastCallAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) FastCallAttr(S.Context, AL));
return;
case ParsedAttr::AT_StdCall:
- D->addAttr(::new (S.Context)
- StdCallAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) StdCallAttr(S.Context, AL));
return;
case ParsedAttr::AT_ThisCall:
- D->addAttr(::new (S.Context)
- ThisCallAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ThisCallAttr(S.Context, AL));
return;
case ParsedAttr::AT_CDecl:
- D->addAttr(::new (S.Context)
- CDeclAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) CDeclAttr(S.Context, AL));
return;
case ParsedAttr::AT_Pascal:
- D->addAttr(::new (S.Context)
- PascalAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) PascalAttr(S.Context, AL));
return;
case ParsedAttr::AT_SwiftCall:
- D->addAttr(::new (S.Context)
- SwiftCallAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) SwiftCallAttr(S.Context, AL));
return;
case ParsedAttr::AT_VectorCall:
- D->addAttr(::new (S.Context)
- VectorCallAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) VectorCallAttr(S.Context, AL));
return;
case ParsedAttr::AT_MSABI:
- D->addAttr(::new (S.Context)
- MSABIAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) MSABIAttr(S.Context, AL));
return;
case ParsedAttr::AT_SysVABI:
- D->addAttr(::new (S.Context)
- SysVABIAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) SysVABIAttr(S.Context, AL));
return;
case ParsedAttr::AT_RegCall:
- D->addAttr(::new (S.Context) RegCallAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) RegCallAttr(S.Context, AL));
return;
case ParsedAttr::AT_Pcs: {
PcsAttr::PCSType PCS;
@@ -4490,28 +4320,20 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
llvm_unreachable("unexpected calling convention in pcs attribute");
}
- D->addAttr(::new (S.Context)
- PcsAttr(AL.getRange(), S.Context, PCS,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) PcsAttr(S.Context, AL, PCS));
return;
}
case ParsedAttr::AT_AArch64VectorPcs:
- D->addAttr(::new(S.Context)
- AArch64VectorPcsAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AArch64VectorPcsAttr(S.Context, AL));
return;
case ParsedAttr::AT_IntelOclBicc:
- D->addAttr(::new (S.Context)
- IntelOclBiccAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) IntelOclBiccAttr(S.Context, AL));
return;
case ParsedAttr::AT_PreserveMost:
- D->addAttr(::new (S.Context) PreserveMostAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) PreserveMostAttr(S.Context, AL));
return;
case ParsedAttr::AT_PreserveAll:
- D->addAttr(::new (S.Context) PreserveAllAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) PreserveAllAttr(S.Context, AL));
return;
default:
llvm_unreachable("unexpected attribute kind");
@@ -4533,9 +4355,71 @@ static void handleSuppressAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// clang-tidy knows about available rules.
DiagnosticIdentifiers.push_back(RuleName);
}
- D->addAttr(::new (S.Context) SuppressAttr(
- AL.getRange(), S.Context, DiagnosticIdentifiers.data(),
- DiagnosticIdentifiers.size(), AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ SuppressAttr(S.Context, AL, DiagnosticIdentifiers.data(),
+ DiagnosticIdentifiers.size()));
+}
+
+static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ TypeSourceInfo *DerefTypeLoc = nullptr;
+ QualType ParmType;
+ if (AL.hasParsedType()) {
+ ParmType = S.GetTypeFromParser(AL.getTypeArg(), &DerefTypeLoc);
+
+ unsigned SelectIdx = ~0U;
+ if (ParmType->isVoidType())
+ SelectIdx = 0;
+ else if (ParmType->isReferenceType())
+ SelectIdx = 1;
+ else if (ParmType->isArrayType())
+ SelectIdx = 2;
+
+ if (SelectIdx != ~0U) {
+ S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument)
+ << SelectIdx << AL;
+ return;
+ }
+ }
+
+ // To check if earlier decl attributes do not conflict the newly parsed ones
+ // we always add (and check) the attribute to the cannonical decl.
+ D = D->getCanonicalDecl();
+ if (AL.getKind() == ParsedAttr::AT_Owner) {
+ if (checkAttrMutualExclusion<PointerAttr>(S, D, AL))
+ return;
+ if (const auto *OAttr = D->getAttr<OwnerAttr>()) {
+ const Type *ExistingDerefType = OAttr->getDerefTypeLoc()
+ ? OAttr->getDerefType().getTypePtr()
+ : nullptr;
+ if (ExistingDerefType != ParmType.getTypePtrOrNull()) {
+ S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
+ << AL << OAttr;
+ S.Diag(OAttr->getLocation(), diag::note_conflicting_attribute);
+ }
+ return;
+ }
+ for (Decl *Redecl : D->redecls()) {
+ Redecl->addAttr(::new (S.Context) OwnerAttr(S.Context, AL, DerefTypeLoc));
+ }
+ } else {
+ if (checkAttrMutualExclusion<OwnerAttr>(S, D, AL))
+ return;
+ if (const auto *PAttr = D->getAttr<PointerAttr>()) {
+ const Type *ExistingDerefType = PAttr->getDerefTypeLoc()
+ ? PAttr->getDerefType().getTypePtr()
+ : nullptr;
+ if (ExistingDerefType != ParmType.getTypePtrOrNull()) {
+ S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
+ << AL << PAttr;
+ S.Diag(PAttr->getLocation(), diag::note_conflicting_attribute);
+ }
+ return;
+ }
+ for (Decl *Redecl : D->redecls()) {
+ Redecl->addAttr(::new (S.Context)
+ PointerAttr(S.Context, AL, DerefTypeLoc));
+ }
+ }
}
bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
@@ -4668,6 +4552,11 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
CC = CC_C;
break;
+ case TargetInfo::CCCR_Error:
+ Diag(Attrs.getLoc(), diag::error_cconv_unsupported)
+ << Attrs << (int)CallingConventionIgnoredReason::ForThisTarget;
+ break;
+
case TargetInfo::CCCR_Warning: {
Diag(Attrs.getLoc(), diag::warn_cconv_unsupported)
<< Attrs << (int)CallingConventionIgnoredReason::ForThisTarget;
@@ -4721,21 +4610,15 @@ static bool isValidSwiftErrorResultType(QualType Ty) {
return isValidSwiftContextType(Ty);
}
-static void handleParameterABIAttr(Sema &S, Decl *D, const ParsedAttr &Attrs,
- ParameterABI Abi) {
- S.AddParameterABIAttr(Attrs.getRange(), D, Abi,
- Attrs.getAttributeSpellingListIndex());
-}
-
-void Sema::AddParameterABIAttr(SourceRange range, Decl *D, ParameterABI abi,
- unsigned spellingIndex) {
+void Sema::AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI,
+ ParameterABI abi) {
QualType type = cast<ParmVarDecl>(D)->getType();
if (auto existingAttr = D->getAttr<ParameterABIAttr>()) {
if (existingAttr->getABI() != abi) {
- Diag(range.getBegin(), diag::err_attributes_are_not_compatible)
- << getParameterABISpelling(abi) << existingAttr;
+ Diag(CI.getLoc(), diag::err_attributes_are_not_compatible)
+ << getParameterABISpelling(abi) << existingAttr;
Diag(existingAttr->getLocation(), diag::note_conflicting_attribute);
return;
}
@@ -4747,32 +4630,26 @@ void Sema::AddParameterABIAttr(SourceRange range, Decl *D, ParameterABI abi,
case ParameterABI::SwiftContext:
if (!isValidSwiftContextType(type)) {
- Diag(range.getBegin(), diag::err_swift_abi_parameter_wrong_type)
- << getParameterABISpelling(abi)
- << /*pointer to pointer */ 0 << type;
+ Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type)
+ << getParameterABISpelling(abi) << /*pointer to pointer */ 0 << type;
}
- D->addAttr(::new (Context)
- SwiftContextAttr(range, Context, spellingIndex));
+ D->addAttr(::new (Context) SwiftContextAttr(Context, CI));
return;
case ParameterABI::SwiftErrorResult:
if (!isValidSwiftErrorResultType(type)) {
- Diag(range.getBegin(), diag::err_swift_abi_parameter_wrong_type)
- << getParameterABISpelling(abi)
- << /*pointer to pointer */ 1 << type;
+ Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type)
+ << getParameterABISpelling(abi) << /*pointer to pointer */ 1 << type;
}
- D->addAttr(::new (Context)
- SwiftErrorResultAttr(range, Context, spellingIndex));
+ D->addAttr(::new (Context) SwiftErrorResultAttr(Context, CI));
return;
case ParameterABI::SwiftIndirectResult:
if (!isValidSwiftIndirectResultType(type)) {
- Diag(range.getBegin(), diag::err_swift_abi_parameter_wrong_type)
- << getParameterABISpelling(abi)
- << /*pointer*/ 0 << type;
+ Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type)
+ << getParameterABISpelling(abi) << /*pointer*/ 0 << type;
}
- D->addAttr(::new (Context)
- SwiftIndirectResultAttr(range, Context, spellingIndex));
+ D->addAttr(::new (Context) SwiftIndirectResultAttr(Context, CI));
return;
}
llvm_unreachable("bad parameter ABI attribute");
@@ -4855,10 +4732,9 @@ static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E,
return ValArg.getAs<Expr>();
}
-void Sema::AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads,
- Expr *MinBlocks, unsigned SpellingListIndex) {
- CUDALaunchBoundsAttr TmpAttr(AttrRange, Context, MaxThreads, MinBlocks,
- SpellingListIndex);
+void Sema::AddLaunchBoundsAttr(Decl *D, const AttributeCommonInfo &CI,
+ Expr *MaxThreads, Expr *MinBlocks) {
+ CUDALaunchBoundsAttr TmpAttr(Context, CI, MaxThreads, MinBlocks);
MaxThreads = makeLaunchBoundsArgExpr(*this, MaxThreads, TmpAttr, 0);
if (MaxThreads == nullptr)
return;
@@ -4869,8 +4745,8 @@ void Sema::AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads,
return;
}
- D->addAttr(::new (Context) CUDALaunchBoundsAttr(
- AttrRange, Context, MaxThreads, MinBlocks, SpellingListIndex));
+ D->addAttr(::new (Context)
+ CUDALaunchBoundsAttr(Context, CI, MaxThreads, MinBlocks));
}
static void handleLaunchBoundsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -4878,9 +4754,8 @@ static void handleLaunchBoundsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
!checkAttributeAtMostNumArgs(S, AL, 2))
return;
- S.AddLaunchBoundsAttr(AL.getRange(), D, AL.getArgAsExpr(0),
- AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr,
- AL.getAttributeSpellingListIndex());
+ S.AddLaunchBoundsAttr(D, AL, AL.getArgAsExpr(0),
+ AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr);
}
static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
@@ -4901,7 +4776,7 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
TypeTagIdx))
return;
- bool IsPointer = AL.getName()->getName() == "pointer_with_type_tag";
+ bool IsPointer = AL.getAttrName()->getName() == "pointer_with_type_tag";
if (IsPointer) {
// Ensure that buffer has a pointer type.
unsigned ArgumentIdxAST = ArgumentIdx.getASTIndex();
@@ -4911,8 +4786,8 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
}
D->addAttr(::new (S.Context) ArgumentWithTypeTagAttr(
- AL.getRange(), S.Context, AL.getArgAsIdent(0)->Ident, ArgumentIdx,
- TypeTagIdx, IsPointer, AL.getAttributeSpellingListIndex()));
+ S.Context, AL, AL.getArgAsIdent(0)->Ident, ArgumentIdx, TypeTagIdx,
+ IsPointer));
}
static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
@@ -4937,12 +4812,9 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
S.GetTypeFromParser(AL.getMatchingCType(), &MatchingCTypeLoc);
assert(MatchingCTypeLoc && "no type source info for attribute argument");
- D->addAttr(::new (S.Context)
- TypeTagForDatatypeAttr(AL.getRange(), S.Context, PointerKind,
- MatchingCTypeLoc,
- AL.getLayoutCompatible(),
- AL.getMustBeNull(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) TypeTagForDatatypeAttr(
+ S.Context, AL, PointerKind, MatchingCTypeLoc, AL.getLayoutCompatible(),
+ AL.getMustBeNull()));
}
static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -4954,9 +4826,8 @@ static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
// ArgCount isn't a parameter index [0;n), it's a count [1;n]
- D->addAttr(::new (S.Context) XRayLogArgsAttr(
- AL.getRange(), S.Context, ArgCount.getSourceIndex(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ XRayLogArgsAttr(S.Context, AL, ArgCount.getSourceIndex()));
}
//===----------------------------------------------------------------------===//
@@ -4983,20 +4854,20 @@ static bool isValidSubjectOfOSAttribute(QualType QT) {
return !PT.isNull() && PT->getAsCXXRecordDecl() != nullptr;
}
-void Sema::AddXConsumedAttr(Decl *D, SourceRange SR, unsigned SpellingIndex,
+void Sema::AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI,
RetainOwnershipKind K,
bool IsTemplateInstantiation) {
ValueDecl *VD = cast<ValueDecl>(D);
switch (K) {
case RetainOwnershipKind::OS:
handleSimpleAttributeOrDiagnose<OSConsumedAttr>(
- *this, VD, SR, SpellingIndex, isValidSubjectOfOSAttribute(VD->getType()),
+ *this, VD, CI, isValidSubjectOfOSAttribute(VD->getType()),
diag::warn_ns_attribute_wrong_parameter_type,
- /*ExtraArgs=*/SR, "os_consumed", /*pointers*/ 1);
+ /*ExtraArgs=*/CI.getRange(), "os_consumed", /*pointers*/ 1);
return;
case RetainOwnershipKind::NS:
handleSimpleAttributeOrDiagnose<NSConsumedAttr>(
- *this, VD, SR, SpellingIndex, isValidSubjectOfNSAttribute(VD->getType()),
+ *this, VD, CI, isValidSubjectOfNSAttribute(VD->getType()),
// These attributes are normally just advisory, but in ARC, ns_consumed
// is significant. Allow non-dependent code to contain inappropriate
@@ -5005,14 +4876,13 @@ void Sema::AddXConsumedAttr(Decl *D, SourceRange SR, unsigned SpellingIndex,
((IsTemplateInstantiation && getLangOpts().ObjCAutoRefCount)
? diag::err_ns_attribute_wrong_parameter_type
: diag::warn_ns_attribute_wrong_parameter_type),
- /*ExtraArgs=*/SR, "ns_consumed", /*objc pointers*/ 0);
+ /*ExtraArgs=*/CI.getRange(), "ns_consumed", /*objc pointers*/ 0);
return;
case RetainOwnershipKind::CF:
handleSimpleAttributeOrDiagnose<CFConsumedAttr>(
- *this, VD, SR, SpellingIndex,
- isValidSubjectOfCFAttribute(VD->getType()),
+ *this, VD, CI, isValidSubjectOfCFAttribute(VD->getType()),
diag::warn_ns_attribute_wrong_parameter_type,
- /*ExtraArgs=*/SR, "cf_consumed", /*pointers*/1);
+ /*ExtraArgs=*/CI.getRange(), "cf_consumed", /*pointers*/ 1);
return;
}
}
@@ -5215,8 +5085,7 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) ObjCReturnsInnerPointerAttr(
- Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCReturnsInnerPointerAttr(S.Context, Attrs));
}
static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
@@ -5236,8 +5105,7 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(
- Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(S.Context, Attrs));
}
static void handleObjCBridgeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5263,9 +5131,7 @@ static void handleObjCBridgeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
- D->addAttr(::new (S.Context)
- ObjCBridgeAttr(AL.getRange(), S.Context, Parm->Ident,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCBridgeAttr(S.Context, AL, Parm->Ident));
}
static void handleObjCBridgeMutableAttr(Sema &S, Decl *D,
@@ -5278,8 +5144,7 @@ static void handleObjCBridgeMutableAttr(Sema &S, Decl *D,
}
D->addAttr(::new (S.Context)
- ObjCBridgeMutableAttr(AL.getRange(), S.Context, Parm->Ident,
- AL.getAttributeSpellingListIndex()));
+ ObjCBridgeMutableAttr(S.Context, AL, Parm->Ident));
}
static void handleObjCBridgeRelatedAttr(Sema &S, Decl *D,
@@ -5294,10 +5159,8 @@ static void handleObjCBridgeRelatedAttr(Sema &S, Decl *D,
AL.getArgAsIdent(1) ? AL.getArgAsIdent(1)->Ident : nullptr;
IdentifierInfo *InstanceMethod =
AL.getArgAsIdent(2) ? AL.getArgAsIdent(2)->Ident : nullptr;
- D->addAttr(::new (S.Context)
- ObjCBridgeRelatedAttr(AL.getRange(), S.Context, RelatedClass,
- ClassMethod, InstanceMethod,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCBridgeRelatedAttr(
+ S.Context, AL, RelatedClass, ClassMethod, InstanceMethod));
}
static void handleObjCDesignatedInitializer(Sema &S, Decl *D,
@@ -5323,9 +5186,7 @@ static void handleObjCDesignatedInitializer(Sema &S, Decl *D,
return;
IFace->setHasDesignatedInitializers();
- D->addAttr(::new (S.Context)
- ObjCDesignatedInitializerAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCDesignatedInitializerAttr(S.Context, AL));
}
static void handleObjCRuntimeName(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5333,9 +5194,7 @@ static void handleObjCRuntimeName(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!S.checkStringLiteralArgumentAttr(AL, 0, MetaDataName))
return;
D->addAttr(::new (S.Context)
- ObjCRuntimeNameAttr(AL.getRange(), S.Context,
- MetaDataName,
- AL.getAttributeSpellingListIndex()));
+ ObjCRuntimeNameAttr(S.Context, AL, MetaDataName));
}
// When a user wants to use objc_boxable with a union or struct
@@ -5352,9 +5211,8 @@ static void handleObjCBoxable(Sema &S, Decl *D, const ParsedAttr &AL) {
}
if (RD) {
- ObjCBoxableAttr *BoxableAttr = ::new (S.Context)
- ObjCBoxableAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex());
+ ObjCBoxableAttr *BoxableAttr =
+ ::new (S.Context) ObjCBoxableAttr(S.Context, AL);
RD->addAttr(BoxableAttr);
if (notify) {
// we need to notify ASTReader/ASTWriter about
@@ -5408,26 +5266,24 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
break;
}
- D->addAttr(::new (S.Context)
- ObjCPreciseLifetimeAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCPreciseLifetimeAttr(S.Context, AL));
}
//===----------------------------------------------------------------------===//
// Microsoft specific attribute handlers.
//===----------------------------------------------------------------------===//
-UuidAttr *Sema::mergeUuidAttr(Decl *D, SourceRange Range,
- unsigned AttrSpellingListIndex, StringRef Uuid) {
+UuidAttr *Sema::mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI,
+ StringRef Uuid) {
if (const auto *UA = D->getAttr<UuidAttr>()) {
if (UA->getGuid().equals_lower(Uuid))
return nullptr;
Diag(UA->getLocation(), diag::err_mismatched_uuid);
- Diag(Range.getBegin(), diag::note_previous_uuid);
+ Diag(CI.getLoc(), diag::note_previous_uuid);
D->dropAttr<UuidAttr>();
}
- return ::new (Context) UuidAttr(Range, Context, Uuid, AttrSpellingListIndex);
+ return ::new (Context) UuidAttr(Context, CI, Uuid);
}
static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5474,8 +5330,7 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (AL.isMicrosoftAttribute()) // Check for [uuid(...)] spelling.
S.Diag(AL.getLoc(), diag::warn_atl_uuid_deprecated);
- UuidAttr *UA = S.mergeUuidAttr(D, AL.getRange(),
- AL.getAttributeSpellingListIndex(), StrRef);
+ UuidAttr *UA = S.mergeUuidAttr(D, AL, StrRef);
if (UA)
D->addAttr(UA);
}
@@ -5487,8 +5342,7 @@ static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
MSInheritanceAttr *IA = S.mergeMSInheritanceAttr(
- D, AL.getRange(), /*BestCase=*/true,
- AL.getAttributeSpellingListIndex(),
+ D, AL, /*BestCase=*/true,
(MSInheritanceAttr::Spelling)AL.getSemanticSpelling());
if (IA) {
D->addAttr(IA);
@@ -5510,8 +5364,7 @@ static void handleDeclspecThreadAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
S.Diag(AL.getLoc(), diag::err_thread_non_global) << "__declspec(thread)";
return;
}
- D->addAttr(::new (S.Context) ThreadAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ThreadAttr(S.Context, AL));
}
static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5542,8 +5395,7 @@ static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end());
D->addAttr(::new (S.Context)
- AbiTagAttr(AL.getRange(), S.Context, Tags.data(), Tags.size(),
- AL.getAttributeSpellingListIndex()));
+ AbiTagAttr(S.Context, AL, Tags.data(), Tags.size()));
}
static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5568,9 +5420,7 @@ static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- unsigned Index = AL.getAttributeSpellingListIndex();
- D->addAttr(::new (S.Context)
- ARMInterruptAttr(AL.getLoc(), S.Context, Kind, Index));
+ D->addAttr(::new (S.Context) ARMInterruptAttr(S.Context, AL, Kind));
}
static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5621,9 +5471,7 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- MSP430InterruptAttr(AL.getLoc(), S.Context, Num,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) MSP430InterruptAttr(S.Context, AL, Num));
D->addAttr(UsedAttr::CreateImplicit(S.Context));
}
@@ -5679,8 +5527,7 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context) MipsInterruptAttr(
- AL.getLoc(), S.Context, Kind, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) MipsInterruptAttr(S.Context, AL, Kind));
}
static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5743,8 +5590,7 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
<< 3 << S.Context.getIntTypeForBitwidth(TypeSize, /*Signed=*/false);
return;
}
- D->addAttr(::new (S.Context) AnyX86InterruptAttr(
- AL.getLoc(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AnyX86InterruptAttr(S.Context, AL));
D->addAttr(UsedAttr::CreateImplicit(S.Context));
}
@@ -5792,9 +5638,8 @@ static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
return;
- FD->addAttr(::new (S.Context) WebAssemblyImportModuleAttr(
- AL.getRange(), S.Context, Str,
- AL.getAttributeSpellingListIndex()));
+ FD->addAttr(::new (S.Context)
+ WebAssemblyImportModuleAttr(S.Context, AL, Str));
}
static void handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5815,9 +5660,7 @@ static void handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
return;
- FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr(
- AL.getRange(), S.Context, Str,
- AL.getAttributeSpellingListIndex()));
+ FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr(S.Context, AL, Str));
}
static void handleRISCVInterruptAttr(Sema &S, Decl *D,
@@ -5875,8 +5718,7 @@ static void handleRISCVInterruptAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) RISCVInterruptAttr(
- AL.getLoc(), S.Context, Kind, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) RISCVInterruptAttr(S.Context, AL, Kind));
}
static void handleInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5936,17 +5778,16 @@ checkAMDGPUFlatWorkGroupSizeArguments(Sema &S, Expr *MinExpr, Expr *MaxExpr,
return false;
}
-void Sema::addAMDGPUFlatWorkGroupSizeAttr(SourceRange AttrRange, Decl *D,
- Expr *MinExpr, Expr *MaxExpr,
- unsigned SpellingListIndex) {
- AMDGPUFlatWorkGroupSizeAttr TmpAttr(AttrRange, Context, MinExpr, MaxExpr,
- SpellingListIndex);
+void Sema::addAMDGPUFlatWorkGroupSizeAttr(Decl *D,
+ const AttributeCommonInfo &CI,
+ Expr *MinExpr, Expr *MaxExpr) {
+ AMDGPUFlatWorkGroupSizeAttr TmpAttr(Context, CI, MinExpr, MaxExpr);
if (checkAMDGPUFlatWorkGroupSizeArguments(*this, MinExpr, MaxExpr, TmpAttr))
return;
- D->addAttr(::new (Context) AMDGPUFlatWorkGroupSizeAttr(
- AttrRange, Context, MinExpr, MaxExpr, SpellingListIndex));
+ D->addAttr(::new (Context)
+ AMDGPUFlatWorkGroupSizeAttr(Context, CI, MinExpr, MaxExpr));
}
static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D,
@@ -5954,8 +5795,7 @@ static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D,
Expr *MinExpr = AL.getArgAsExpr(0);
Expr *MaxExpr = AL.getArgAsExpr(1);
- S.addAMDGPUFlatWorkGroupSizeAttr(AL.getRange(), D, MinExpr, MaxExpr,
- AL.getAttributeSpellingListIndex());
+ S.addAMDGPUFlatWorkGroupSizeAttr(D, AL, MinExpr, MaxExpr);
}
static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr,
@@ -5992,17 +5832,15 @@ static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr,
return false;
}
-void Sema::addAMDGPUWavesPerEUAttr(SourceRange AttrRange, Decl *D,
- Expr *MinExpr, Expr *MaxExpr,
- unsigned SpellingListIndex) {
- AMDGPUWavesPerEUAttr TmpAttr(AttrRange, Context, MinExpr, MaxExpr,
- SpellingListIndex);
+void Sema::addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI,
+ Expr *MinExpr, Expr *MaxExpr) {
+ AMDGPUWavesPerEUAttr TmpAttr(Context, CI, MinExpr, MaxExpr);
if (checkAMDGPUWavesPerEUArguments(*this, MinExpr, MaxExpr, TmpAttr))
return;
- D->addAttr(::new (Context) AMDGPUWavesPerEUAttr(AttrRange, Context, MinExpr,
- MaxExpr, SpellingListIndex));
+ D->addAttr(::new (Context)
+ AMDGPUWavesPerEUAttr(Context, CI, MinExpr, MaxExpr));
}
static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -6013,8 +5851,7 @@ static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expr *MinExpr = AL.getArgAsExpr(0);
Expr *MaxExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr;
- S.addAMDGPUWavesPerEUAttr(AL.getRange(), D, MinExpr, MaxExpr,
- AL.getAttributeSpellingListIndex());
+ S.addAMDGPUWavesPerEUAttr(D, AL, MinExpr, MaxExpr);
}
static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -6023,9 +5860,7 @@ static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!checkUInt32Argument(S, AL, NumSGPRExpr, NumSGPR))
return;
- D->addAttr(::new (S.Context)
- AMDGPUNumSGPRAttr(AL.getLoc(), S.Context, NumSGPR,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AMDGPUNumSGPRAttr(S.Context, AL, NumSGPR));
}
static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -6034,9 +5869,7 @@ static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!checkUInt32Argument(S, AL, NumVGPRExpr, NumVGPR))
return;
- D->addAttr(::new (S.Context)
- AMDGPUNumVGPRAttr(AL.getLoc(), S.Context, NumVGPR,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AMDGPUNumVGPRAttr(S.Context, AL, NumVGPR));
}
static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D,
@@ -6059,9 +5892,7 @@ static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context)
- X86ForceAlignArgPointerAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(S.Context, AL));
}
static void handleLayoutVersion(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -6082,26 +5913,24 @@ static void handleLayoutVersion(Sema &S, Decl *D, const ParsedAttr &AL) {
// have to multiply by 100 now.
Version *= 100;
- D->addAttr(::new (S.Context)
- LayoutVersionAttr(AL.getRange(), S.Context, Version,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) LayoutVersionAttr(S.Context, AL, Version));
}
-DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range,
- unsigned AttrSpellingListIndex) {
+DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D,
+ const AttributeCommonInfo &CI) {
if (D->hasAttr<DLLExportAttr>()) {
- Diag(Range.getBegin(), diag::warn_attribute_ignored) << "'dllimport'";
+ Diag(CI.getLoc(), diag::warn_attribute_ignored) << "'dllimport'";
return nullptr;
}
if (D->hasAttr<DLLImportAttr>())
return nullptr;
- return ::new (Context) DLLImportAttr(Range, Context, AttrSpellingListIndex);
+ return ::new (Context) DLLImportAttr(Context, CI);
}
-DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range,
- unsigned AttrSpellingListIndex) {
+DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D,
+ const AttributeCommonInfo &CI) {
if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) {
Diag(Import->getLocation(), diag::warn_attribute_ignored) << Import;
D->dropAttr<DLLImportAttr>();
@@ -6110,7 +5939,7 @@ DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range,
if (D->hasAttr<DLLExportAttr>())
return nullptr;
- return ::new (Context) DLLExportAttr(Range, Context, AttrSpellingListIndex);
+ return ::new (Context) DLLExportAttr(Context, CI);
}
static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) {
@@ -6138,48 +5967,46 @@ static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) {
}
}
- unsigned Index = A.getAttributeSpellingListIndex();
Attr *NewAttr = A.getKind() == ParsedAttr::AT_DLLExport
- ? (Attr *)S.mergeDLLExportAttr(D, A.getRange(), Index)
- : (Attr *)S.mergeDLLImportAttr(D, A.getRange(), Index);
+ ? (Attr *)S.mergeDLLExportAttr(D, A)
+ : (Attr *)S.mergeDLLImportAttr(D, A);
if (NewAttr)
D->addAttr(NewAttr);
}
MSInheritanceAttr *
-Sema::mergeMSInheritanceAttr(Decl *D, SourceRange Range, bool BestCase,
- unsigned AttrSpellingListIndex,
+Sema::mergeMSInheritanceAttr(Decl *D, const AttributeCommonInfo &CI,
+ bool BestCase,
MSInheritanceAttr::Spelling SemanticSpelling) {
if (MSInheritanceAttr *IA = D->getAttr<MSInheritanceAttr>()) {
if (IA->getSemanticSpelling() == SemanticSpelling)
return nullptr;
Diag(IA->getLocation(), diag::err_mismatched_ms_inheritance)
<< 1 /*previous declaration*/;
- Diag(Range.getBegin(), diag::note_previous_ms_inheritance);
+ Diag(CI.getLoc(), diag::note_previous_ms_inheritance);
D->dropAttr<MSInheritanceAttr>();
}
auto *RD = cast<CXXRecordDecl>(D);
if (RD->hasDefinition()) {
- if (checkMSInheritanceAttrOnDefinition(RD, Range, BestCase,
+ if (checkMSInheritanceAttrOnDefinition(RD, CI.getRange(), BestCase,
SemanticSpelling)) {
return nullptr;
}
} else {
if (isa<ClassTemplatePartialSpecializationDecl>(RD)) {
- Diag(Range.getBegin(), diag::warn_ignored_ms_inheritance)
+ Diag(CI.getLoc(), diag::warn_ignored_ms_inheritance)
<< 1 /*partial specialization*/;
return nullptr;
}
if (RD->getDescribedClassTemplate()) {
- Diag(Range.getBegin(), diag::warn_ignored_ms_inheritance)
+ Diag(CI.getLoc(), diag::warn_ignored_ms_inheritance)
<< 0 /*primary template*/;
return nullptr;
}
}
- return ::new (Context)
- MSInheritanceAttr(Range, Context, BestCase, AttrSpellingListIndex);
+ return ::new (Context) MSInheritanceAttr(Context, CI, BestCase);
}
static void handleCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -6202,8 +6029,7 @@ static void handleCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!N.equals_lower("mutex") && !N.equals_lower("role"))
S.Diag(LiteralLoc, diag::warn_invalid_capability_name) << N;
- D->addAttr(::new (S.Context) CapabilityAttr(AL.getRange(), S.Context, N,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) CapabilityAttr(S.Context, AL, N));
}
static void handleAssertCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -6211,9 +6037,8 @@ static void handleAssertCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!checkLockFunAttrCommon(S, D, AL, Args))
return;
- D->addAttr(::new (S.Context) AssertCapabilityAttr(AL.getRange(), S.Context,
- Args.data(), Args.size(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ AssertCapabilityAttr(S.Context, AL, Args.data(), Args.size()));
}
static void handleAcquireCapabilityAttr(Sema &S, Decl *D,
@@ -6222,10 +6047,8 @@ static void handleAcquireCapabilityAttr(Sema &S, Decl *D,
if (!checkLockFunAttrCommon(S, D, AL, Args))
return;
- D->addAttr(::new (S.Context) AcquireCapabilityAttr(AL.getRange(),
- S.Context,
- Args.data(), Args.size(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AcquireCapabilityAttr(S.Context, AL, Args.data(),
+ Args.size()));
}
static void handleTryAcquireCapabilityAttr(Sema &S, Decl *D,
@@ -6234,12 +6057,8 @@ static void handleTryAcquireCapabilityAttr(Sema &S, Decl *D,
if (!checkTryLockFunAttrCommon(S, D, AL, Args))
return;
- D->addAttr(::new (S.Context) TryAcquireCapabilityAttr(AL.getRange(),
- S.Context,
- AL.getArgAsExpr(0),
- Args.data(),
- Args.size(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) TryAcquireCapabilityAttr(
+ S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size()));
}
static void handleReleaseCapabilityAttr(Sema &S, Decl *D,
@@ -6248,9 +6067,8 @@ static void handleReleaseCapabilityAttr(Sema &S, Decl *D,
SmallVector<Expr *, 1> Args;
checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 0, true);
- D->addAttr(::new (S.Context) ReleaseCapabilityAttr(
- AL.getRange(), S.Context, Args.data(), Args.size(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ReleaseCapabilityAttr(S.Context, AL, Args.data(),
+ Args.size()));
}
static void handleRequiresCapabilityAttr(Sema &S, Decl *D,
@@ -6265,8 +6083,7 @@ static void handleRequiresCapabilityAttr(Sema &S, Decl *D,
return;
RequiresCapabilityAttr *RCA = ::new (S.Context)
- RequiresCapabilityAttr(AL.getRange(), S.Context, Args.data(),
- Args.size(), AL.getAttributeSpellingListIndex());
+ RequiresCapabilityAttr(S.Context, AL, Args.data(), Args.size());
D->addAttr(RCA);
}
@@ -6298,9 +6115,7 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!S.getLangOpts().CPlusPlus14 && AL.isCXX11Attribute() && !AL.isGNUScope())
S.Diag(AL.getLoc(), diag::ext_cxx14_attr) << AL;
- D->addAttr(::new (S.Context)
- DeprecatedAttr(AL.getRange(), S.Context, Str, Replacement,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) DeprecatedAttr(S.Context, AL, Str, Replacement));
}
static bool isGlobalVar(const Decl *D) {
@@ -6331,14 +6146,13 @@ static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Sanitizers.push_back(SanitizerName);
}
- D->addAttr(::new (S.Context) NoSanitizeAttr(
- AL.getRange(), S.Context, Sanitizers.data(), Sanitizers.size(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NoSanitizeAttr(S.Context, AL, Sanitizers.data(),
+ Sanitizers.size()));
}
static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D,
const ParsedAttr &AL) {
- StringRef AttrName = AL.getName()->getName();
+ StringRef AttrName = AL.getAttrName()->getName();
normalizeName(AttrName);
StringRef SanitizerName = llvm::StringSwitch<StringRef>(AttrName)
.Case("no_address_safety_analysis", "address")
@@ -6361,8 +6175,10 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D,
if (AL.isC2xAttribute() || AL.isCXX11Attribute())
TranslatedSpellingIndex = 1;
- D->addAttr(::new (S.Context) NoSanitizeAttr(
- AL.getRange(), S.Context, &SanitizerName, 1, TranslatedSpellingIndex));
+ AttributeCommonInfo Info = AL;
+ Info.setAttributeSpellingListIndex(TranslatedSpellingIndex);
+ D->addAttr(::new (S.Context)
+ NoSanitizeAttr(S.Context, Info, &SanitizerName, 1));
}
static void handleInternalLinkageAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -6431,7 +6247,7 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (D->getAttr<OpenCLAccessAttr>()->getSemanticSpelling() ==
AL.getSemanticSpelling()) {
S.Diag(AL.getLoc(), diag::warn_duplicate_declspec)
- << AL.getName()->getName() << AL.getRange();
+ << AL.getAttrName()->getName() << AL.getRange();
} else {
S.Diag(AL.getLoc(), diag::err_opencl_multiple_access_qualifiers)
<< D->getSourceRange();
@@ -6447,7 +6263,7 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// qualifier is a compilation error.
if (const auto *PDecl = dyn_cast<ParmVarDecl>(D)) {
const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr();
- if (AL.getName()->getName().find("read_write") != StringRef::npos) {
+ if (AL.getAttrName()->getName().find("read_write") != StringRef::npos) {
if ((!S.getLangOpts().OpenCLCPlusPlus &&
S.getLangOpts().OpenCLVersion < 200) ||
DeclTy->isPipeType()) {
@@ -6459,8 +6275,7 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
- D->addAttr(::new (S.Context) OpenCLAccessAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) OpenCLAccessAttr(S.Context, AL));
}
static void handleDestroyAttr(Sema &S, Decl *D, const ParsedAttr &A) {
@@ -6479,9 +6294,7 @@ static void handleDestroyAttr(Sema &S, Decl *D, const ParsedAttr &A) {
static void handleUninitializedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
assert(cast<VarDecl>(D)->getStorageDuration() == SD_Automatic &&
"uninitialized is only valid on automatic duration variables");
- unsigned Index = AL.getAttributeSpellingListIndex();
- D->addAttr(::new (S.Context)
- UninitializedAttr(AL.getLoc(), S.Context, Index));
+ D->addAttr(::new (S.Context) UninitializedAttr(S.Context, AL));
}
static bool tryMakeVariablePseudoStrong(Sema &S, VarDecl *VD,
@@ -6932,9 +6745,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_CFConsumed:
case ParsedAttr::AT_NSConsumed:
case ParsedAttr::AT_OSConsumed:
- S.AddXConsumedAttr(D, AL.getRange(), AL.getAttributeSpellingListIndex(),
- parsedAttrToRetainOwnershipKind(AL),
- /*IsTemplateInstantiation=*/false);
+ S.AddXConsumedAttr(D, AL, parsedAttrToRetainOwnershipKind(AL),
+ /*IsTemplateInstantiation=*/false);
break;
case ParsedAttr::AT_NSConsumesSelf:
handleSimpleAttribute<NSConsumesSelfAttr>(S, D, AL);
@@ -6975,8 +6787,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_VecTypeHint:
handleVecTypeHint(S, D, AL);
break;
- case ParsedAttr::AT_RequireConstantInit:
- handleSimpleAttribute<RequireConstantInitAttr>(S, D, AL);
+ case ParsedAttr::AT_ConstInit:
+ handleSimpleAttribute<ConstInitAttr>(S, D, AL);
break;
case ParsedAttr::AT_InitPriority:
handleInitPriorityAttr(S, D, AL);
@@ -7116,6 +6928,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
// Interacts with -fstack-protector options.
handleSimpleAttribute<NoStackProtectorAttr>(S, D, AL);
break;
+ case ParsedAttr::AT_CFICanonicalJumpTable:
+ handleSimpleAttribute<CFICanonicalJumpTableAttr>(S, D, AL);
+ break;
case ParsedAttr::AT_StdCall:
case ParsedAttr::AT_CDecl:
case ParsedAttr::AT_FastCall:
@@ -7136,6 +6951,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_Suppress:
handleSuppressAttr(S, D, AL);
break;
+ case ParsedAttr::AT_Owner:
+ case ParsedAttr::AT_Pointer:
+ handleLifetimeCategoryAttr(S, D, AL);
+ break;
case ParsedAttr::AT_OpenCLKernel:
handleSimpleAttribute<OpenCLKernelAttr>(S, D, AL);
break;
@@ -7146,13 +6965,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleOpenCLNoSVMAttr(S, D, AL);
break;
case ParsedAttr::AT_SwiftContext:
- handleParameterABIAttr(S, D, AL, ParameterABI::SwiftContext);
+ S.AddParameterABIAttr(D, AL, ParameterABI::SwiftContext);
break;
case ParsedAttr::AT_SwiftErrorResult:
- handleParameterABIAttr(S, D, AL, ParameterABI::SwiftErrorResult);
+ S.AddParameterABIAttr(D, AL, ParameterABI::SwiftErrorResult);
break;
case ParsedAttr::AT_SwiftIndirectResult:
- handleParameterABIAttr(S, D, AL, ParameterABI::SwiftIndirectResult);
+ S.AddParameterABIAttr(D, AL, ParameterABI::SwiftIndirectResult);
break;
case ParsedAttr::AT_InternalLinkage:
handleInternalLinkageAttr(S, D, AL);
@@ -7526,9 +7345,10 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...))
IdentifierInfo *NDId = ND->getIdentifier();
NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias(), W.getLocation());
- NewD->addAttr(AliasAttr::CreateImplicit(Context, NDId->getName(),
- W.getLocation()));
- NewD->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation()));
+ NewD->addAttr(
+ AliasAttr::CreateImplicit(Context, NDId->getName(), W.getLocation()));
+ NewD->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation(),
+ AttributeCommonInfo::AS_Pragma));
WeakTopLevelDecl.push_back(NewD);
// FIXME: "hideous" code from Sema::LazilyCreateBuiltin
// to insert Decl at TU scope, sorry.
@@ -7539,7 +7359,8 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
PushOnScopeChains(NewD, S);
CurContext = SavedContext;
} else { // just add weak to existing
- ND->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation()));
+ ND->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation(),
+ AttributeCommonInfo::AS_Pragma));
}
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 9a6385f28319..ff90b9548e29 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeOrdering.h"
+#include "clang/Basic/AttributeCommonInfo.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/LiteralSupport.h"
@@ -774,6 +775,13 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
return nullptr;
}
+ // C++2a [dcl.struct.bind]p1:
+ // A cv that includes volatile is deprecated
+ if ((DS.getTypeQualifiers() & DeclSpec::TQ_volatile) &&
+ getLangOpts().CPlusPlus2a)
+ Diag(DS.getVolatileSpecLoc(),
+ diag::warn_deprecated_volatile_structured_binding);
+
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType R = TInfo->getType();
@@ -1030,8 +1038,10 @@ static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T,
TemplateArgumentListInfo Args(Loc, Loc);
Args.addArgument(getTrivialTypeTemplateArgument(S, Loc, T));
- // If there's no tuple_size specialization, it's not tuple-like.
- if (lookupStdTypeTraitMember(S, R, Loc, "tuple_size", Args, /*DiagID*/0))
+ // If there's no tuple_size specialization or the lookup of 'value' is empty,
+ // it's not tuple-like.
+ if (lookupStdTypeTraitMember(S, R, Loc, "tuple_size", Args, /*DiagID*/ 0) ||
+ R.empty())
return IsTupleLike::NotTupleLike;
// If we get this far, we've committed to the tuple interpretation, but
@@ -1048,11 +1058,6 @@ static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T,
}
} Diagnoser(R, Args);
- if (R.empty()) {
- Diagnoser.diagnoseNotICE(S, Loc, SourceRange());
- return IsTupleLike::Error;
- }
-
ExprResult E =
S.BuildDeclarationNameExpr(CXXScopeSpec(), R, /*NeedsADL*/false);
if (E.isInvalid())
@@ -1228,7 +1233,8 @@ static bool checkTupleLikeDecomposition(Sema &S,
if (E.isInvalid())
return true;
RefVD->setInit(E.get());
- RefVD->checkInitIsICE();
+ if (!E.get()->isValueDependent())
+ RefVD->checkInitIsICE();
E = S.BuildDeclarationNameExpr(CXXScopeSpec(),
DeclarationNameInfo(B->getDeclName(), Loc),
@@ -1569,11 +1575,64 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
}
}
+/// Check that the given type is a literal type. Issue a diagnostic if not,
+/// if Kind is Diagnose.
+/// \return \c true if a problem has been found (and optionally diagnosed).
+template <typename... Ts>
+static bool CheckLiteralType(Sema &SemaRef, Sema::CheckConstexprKind Kind,
+ SourceLocation Loc, QualType T, unsigned DiagID,
+ Ts &&...DiagArgs) {
+ if (T->isDependentType())
+ return false;
+
+ switch (Kind) {
+ case Sema::CheckConstexprKind::Diagnose:
+ return SemaRef.RequireLiteralType(Loc, T, DiagID,
+ std::forward<Ts>(DiagArgs)...);
+
+ case Sema::CheckConstexprKind::CheckValid:
+ return !T->isLiteralType(SemaRef.Context);
+ }
+
+ llvm_unreachable("unknown CheckConstexprKind");
+}
+
+/// Determine whether a destructor cannot be constexpr due to
+static bool CheckConstexprDestructorSubobjects(Sema &SemaRef,
+ const CXXDestructorDecl *DD,
+ Sema::CheckConstexprKind Kind) {
+ auto Check = [&](SourceLocation Loc, QualType T, const FieldDecl *FD) {
+ const CXXRecordDecl *RD =
+ T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+ if (!RD || RD->hasConstexprDestructor())
+ return true;
+
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ SemaRef.Diag(DD->getLocation(), diag::err_constexpr_dtor_subobject)
+ << DD->getConstexprKind() << !FD
+ << (FD ? FD->getDeclName() : DeclarationName()) << T;
+ SemaRef.Diag(Loc, diag::note_constexpr_dtor_subobject)
+ << !FD << (FD ? FD->getDeclName() : DeclarationName()) << T;
+ }
+ return false;
+ };
+
+ const CXXRecordDecl *RD = DD->getParent();
+ for (const CXXBaseSpecifier &B : RD->bases())
+ if (!Check(B.getBaseTypeLoc(), B.getType(), nullptr))
+ return false;
+ for (const FieldDecl *FD : RD->fields())
+ if (!Check(FD->getLocation(), FD->getType(), FD))
+ return false;
+ return true;
+}
+
// CheckConstexprParameterTypes - Check whether a function's parameter types
// are all literal types. If so, return true. If not, produce a suitable
// diagnostic and return false.
static bool CheckConstexprParameterTypes(Sema &SemaRef,
- const FunctionDecl *FD) {
+ const FunctionDecl *FD,
+ Sema::CheckConstexprKind Kind) {
unsigned ArgIndex = 0;
const FunctionProtoType *FT = FD->getType()->getAs<FunctionProtoType>();
for (FunctionProtoType::param_type_iterator i = FT->param_type_begin(),
@@ -1581,11 +1640,10 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef,
i != e; ++i, ++ArgIndex) {
const ParmVarDecl *PD = FD->getParamDecl(ArgIndex);
SourceLocation ParamLoc = PD->getLocation();
- if (!(*i)->isDependentType() &&
- SemaRef.RequireLiteralType(
- ParamLoc, *i, diag::err_constexpr_non_literal_param, ArgIndex + 1,
- PD->getSourceRange(), isa<CXXConstructorDecl>(FD),
- FD->isConsteval()))
+ if (CheckLiteralType(SemaRef, Kind, ParamLoc, *i,
+ diag::err_constexpr_non_literal_param, ArgIndex + 1,
+ PD->getSourceRange(), isa<CXXConstructorDecl>(FD),
+ FD->isConsteval()))
return false;
}
return true;
@@ -1605,13 +1663,18 @@ static unsigned getRecordDiagFromTagKind(TagTypeKind Tag) {
}
}
-// CheckConstexprFunctionDecl - Check whether a function declaration satisfies
-// the requirements of a constexpr function definition or a constexpr
-// constructor definition. If so, return true. If not, produce appropriate
-// diagnostics and return false.
+static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
+ Stmt *Body,
+ Sema::CheckConstexprKind Kind);
+
+// Check whether a function declaration satisfies the requirements of a
+// constexpr function definition or a constexpr constructor definition. If so,
+// return true. If not, produce appropriate diagnostics (unless asked not to by
+// Kind) and return false.
//
// This implements C++11 [dcl.constexpr]p3,4, as amended by DR1360.
-bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
+bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD,
+ CheckConstexprKind Kind) {
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
if (MD && MD->isInstance()) {
// C++11 [dcl.constexpr]p4:
@@ -1619,10 +1682,13 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
// constraints:
// - the class shall not have any virtual base classes;
//
- // FIXME: This only applies to constructors, not arbitrary member
- // functions.
+ // FIXME: This only applies to constructors and destructors, not arbitrary
+ // member functions.
const CXXRecordDecl *RD = MD->getParent();
if (RD->getNumVBases()) {
+ if (Kind == CheckConstexprKind::CheckValid)
+ return false;
+
Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base)
<< isa<CXXConstructorDecl>(NewFD)
<< getRecordDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases();
@@ -1641,8 +1707,12 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD);
if (Method && Method->isVirtual()) {
if (getLangOpts().CPlusPlus2a) {
- Diag(Method->getLocation(), diag::warn_cxx17_compat_constexpr_virtual);
+ if (Kind == CheckConstexprKind::Diagnose)
+ Diag(Method->getLocation(), diag::warn_cxx17_compat_constexpr_virtual);
} else {
+ if (Kind == CheckConstexprKind::CheckValid)
+ return false;
+
Method = Method->getCanonicalDecl();
Diag(Method->getLocation(), diag::err_constexpr_virtual);
@@ -1660,18 +1730,32 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
// - its return type shall be a literal type;
QualType RT = NewFD->getReturnType();
- if (!RT->isDependentType() &&
- RequireLiteralType(NewFD->getLocation(), RT,
- diag::err_constexpr_non_literal_return,
- NewFD->isConsteval()))
+ if (CheckLiteralType(*this, Kind, NewFD->getLocation(), RT,
+ diag::err_constexpr_non_literal_return,
+ NewFD->isConsteval()))
return false;
}
+ if (auto *Dtor = dyn_cast<CXXDestructorDecl>(NewFD)) {
+ // A destructor can be constexpr only if the defaulted destructor could be;
+ // we don't need to check the members and bases if we already know they all
+ // have constexpr destructors.
+ if (!Dtor->getParent()->defaultedDestructorIsConstexpr()) {
+ if (Kind == CheckConstexprKind::CheckValid)
+ return false;
+ if (!CheckConstexprDestructorSubobjects(*this, Dtor, Kind))
+ return false;
+ }
+ }
+
// - each of its parameter types shall be a literal type;
- if (!CheckConstexprParameterTypes(*this, NewFD))
+ if (!CheckConstexprParameterTypes(*this, NewFD, Kind))
return false;
- return true;
+ Stmt *Body = NewFD->getBody();
+ assert(Body &&
+ "CheckConstexprFunctionDefinition called on function with no body");
+ return CheckConstexprFunctionBody(*this, NewFD, Body, Kind);
}
/// Check the given declaration statement is legal within a constexpr function
@@ -1680,7 +1764,8 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
/// \return true if the body is OK (maybe only as an extension), false if we
/// have diagnosed a problem.
static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
- DeclStmt *DS, SourceLocation &Cxx1yLoc) {
+ DeclStmt *DS, SourceLocation &Cxx1yLoc,
+ Sema::CheckConstexprKind Kind) {
// C++11 [dcl.constexpr]p3 and p4:
// The definition of a constexpr function(p3) or constructor(p4) [...] shall
// contain only
@@ -1704,10 +1789,12 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
const auto *TN = cast<TypedefNameDecl>(DclIt);
if (TN->getUnderlyingType()->isVariablyModifiedType()) {
// Don't allow variably-modified types in constexpr functions.
- TypeLoc TL = TN->getTypeSourceInfo()->getTypeLoc();
- SemaRef.Diag(TL.getBeginLoc(), diag::err_constexpr_vla)
- << TL.getSourceRange() << TL.getType()
- << isa<CXXConstructorDecl>(Dcl);
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ TypeLoc TL = TN->getTypeSourceInfo()->getTypeLoc();
+ SemaRef.Diag(TL.getBeginLoc(), diag::err_constexpr_vla)
+ << TL.getSourceRange() << TL.getType()
+ << isa<CXXConstructorDecl>(Dcl);
+ }
return false;
}
continue;
@@ -1716,12 +1803,17 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
case Decl::Enum:
case Decl::CXXRecord:
// C++1y allows types to be defined, not just declared.
- if (cast<TagDecl>(DclIt)->isThisDeclarationADefinition())
- SemaRef.Diag(DS->getBeginLoc(),
- SemaRef.getLangOpts().CPlusPlus14
- ? diag::warn_cxx11_compat_constexpr_type_definition
- : diag::ext_constexpr_type_definition)
- << isa<CXXConstructorDecl>(Dcl);
+ if (cast<TagDecl>(DclIt)->isThisDeclarationADefinition()) {
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ SemaRef.Diag(DS->getBeginLoc(),
+ SemaRef.getLangOpts().CPlusPlus14
+ ? diag::warn_cxx11_compat_constexpr_type_definition
+ : diag::ext_constexpr_type_definition)
+ << isa<CXXConstructorDecl>(Dcl);
+ } else if (!SemaRef.getLangOpts().CPlusPlus14) {
+ return false;
+ }
+ }
continue;
case Decl::EnumConstant:
@@ -1735,35 +1827,47 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
case Decl::Decomposition: {
// C++1y [dcl.constexpr]p3 allows anything except:
// a definition of a variable of non-literal type or of static or
- // thread storage duration or for which no initialization is performed.
+ // thread storage duration or [before C++2a] for which no
+ // initialization is performed.
const auto *VD = cast<VarDecl>(DclIt);
if (VD->isThisDeclarationADefinition()) {
if (VD->isStaticLocal()) {
- SemaRef.Diag(VD->getLocation(),
- diag::err_constexpr_local_var_static)
- << isa<CXXConstructorDecl>(Dcl)
- << (VD->getTLSKind() == VarDecl::TLS_Dynamic);
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ SemaRef.Diag(VD->getLocation(),
+ diag::err_constexpr_local_var_static)
+ << isa<CXXConstructorDecl>(Dcl)
+ << (VD->getTLSKind() == VarDecl::TLS_Dynamic);
+ }
return false;
}
- if (!VD->getType()->isDependentType() &&
- SemaRef.RequireLiteralType(
- VD->getLocation(), VD->getType(),
- diag::err_constexpr_local_var_non_literal_type,
- isa<CXXConstructorDecl>(Dcl)))
+ if (CheckLiteralType(SemaRef, Kind, VD->getLocation(), VD->getType(),
+ diag::err_constexpr_local_var_non_literal_type,
+ isa<CXXConstructorDecl>(Dcl)))
return false;
if (!VD->getType()->isDependentType() &&
!VD->hasInit() && !VD->isCXXForRangeDecl()) {
- SemaRef.Diag(VD->getLocation(),
- diag::err_constexpr_local_var_no_init)
- << isa<CXXConstructorDecl>(Dcl);
- return false;
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ SemaRef.Diag(
+ VD->getLocation(),
+ SemaRef.getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_constexpr_local_var_no_init
+ : diag::ext_constexpr_local_var_no_init)
+ << isa<CXXConstructorDecl>(Dcl);
+ } else if (!SemaRef.getLangOpts().CPlusPlus2a) {
+ return false;
+ }
+ continue;
}
}
- SemaRef.Diag(VD->getLocation(),
- SemaRef.getLangOpts().CPlusPlus14
- ? diag::warn_cxx11_compat_constexpr_local_var
- : diag::ext_constexpr_local_var)
- << isa<CXXConstructorDecl>(Dcl);
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ SemaRef.Diag(VD->getLocation(),
+ SemaRef.getLangOpts().CPlusPlus14
+ ? diag::warn_cxx11_compat_constexpr_local_var
+ : diag::ext_constexpr_local_var)
+ << isa<CXXConstructorDecl>(Dcl);
+ } else if (!SemaRef.getLangOpts().CPlusPlus14) {
+ return false;
+ }
continue;
}
@@ -1776,8 +1880,10 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
continue;
default:
- SemaRef.Diag(DS->getBeginLoc(), diag::err_constexpr_body_invalid_stmt)
- << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ SemaRef.Diag(DS->getBeginLoc(), diag::err_constexpr_body_invalid_stmt)
+ << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
+ }
return false;
}
}
@@ -1792,17 +1898,28 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
/// struct or union nested within the class being checked.
/// \param Inits All declarations, including anonymous struct/union members and
/// indirect members, for which any initialization was provided.
-/// \param Diagnosed Set to true if an error is produced.
-static void CheckConstexprCtorInitializer(Sema &SemaRef,
+/// \param Diagnosed Whether we've emitted the error message yet. Used to attach
+/// multiple notes for different members to the same error.
+/// \param Kind Whether we're diagnosing a constructor as written or determining
+/// whether the formal requirements are satisfied.
+/// \return \c false if we're checking for validity and the constructor does
+/// not satisfy the requirements on a constexpr constructor.
+static bool CheckConstexprCtorInitializer(Sema &SemaRef,
const FunctionDecl *Dcl,
FieldDecl *Field,
llvm::SmallSet<Decl*, 16> &Inits,
- bool &Diagnosed) {
+ bool &Diagnosed,
+ Sema::CheckConstexprKind Kind) {
+ // In C++20 onwards, there's nothing to check for validity.
+ if (Kind == Sema::CheckConstexprKind::CheckValid &&
+ SemaRef.getLangOpts().CPlusPlus2a)
+ return true;
+
if (Field->isInvalidDecl())
- return;
+ return true;
if (Field->isUnnamedBitfield())
- return;
+ return true;
// Anonymous unions with no variant members and empty anonymous structs do not
// need to be explicitly initialized. FIXME: Anonymous structs that contain no
@@ -1811,22 +1928,33 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef,
(Field->getType()->isUnionType()
? !Field->getType()->getAsCXXRecordDecl()->hasVariantMembers()
: Field->getType()->getAsCXXRecordDecl()->isEmpty()))
- return;
+ return true;
if (!Inits.count(Field)) {
- if (!Diagnosed) {
- SemaRef.Diag(Dcl->getLocation(), diag::err_constexpr_ctor_missing_init);
- Diagnosed = true;
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ if (!Diagnosed) {
+ SemaRef.Diag(Dcl->getLocation(),
+ SemaRef.getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_constexpr_ctor_missing_init
+ : diag::ext_constexpr_ctor_missing_init);
+ Diagnosed = true;
+ }
+ SemaRef.Diag(Field->getLocation(),
+ diag::note_constexpr_ctor_missing_init);
+ } else if (!SemaRef.getLangOpts().CPlusPlus2a) {
+ return false;
}
- SemaRef.Diag(Field->getLocation(), diag::note_constexpr_ctor_missing_init);
} else if (Field->isAnonymousStructOrUnion()) {
const RecordDecl *RD = Field->getType()->castAs<RecordType>()->getDecl();
for (auto *I : RD->fields())
// If an anonymous union contains an anonymous struct of which any member
// is initialized, all members must be initialized.
if (!RD->isUnion() || Inits.count(I))
- CheckConstexprCtorInitializer(SemaRef, Dcl, I, Inits, Diagnosed);
+ if (!CheckConstexprCtorInitializer(SemaRef, Dcl, I, Inits, Diagnosed,
+ Kind))
+ return false;
}
+ return true;
}
/// Check the provided statement is allowed in a constexpr function
@@ -1834,7 +1962,8 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef,
static bool
CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
SmallVectorImpl<SourceLocation> &ReturnStmts,
- SourceLocation &Cxx1yLoc, SourceLocation &Cxx2aLoc) {
+ SourceLocation &Cxx1yLoc, SourceLocation &Cxx2aLoc,
+ Sema::CheckConstexprKind Kind) {
// - its function-body shall be [...] a compound-statement that contains only
switch (S->getStmtClass()) {
case Stmt::NullStmtClass:
@@ -1847,7 +1976,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
// - using-directives,
// - typedef declarations and alias-declarations that do not define
// classes or enumerations,
- if (!CheckConstexprDeclStmt(SemaRef, Dcl, cast<DeclStmt>(S), Cxx1yLoc))
+ if (!CheckConstexprDeclStmt(SemaRef, Dcl, cast<DeclStmt>(S), Cxx1yLoc, Kind))
return false;
return true;
@@ -1871,7 +2000,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
CompoundStmt *CompStmt = cast<CompoundStmt>(S);
for (auto *BodyIt : CompStmt->body()) {
if (!CheckConstexprFunctionStmt(SemaRef, Dcl, BodyIt, ReturnStmts,
- Cxx1yLoc, Cxx2aLoc))
+ Cxx1yLoc, Cxx2aLoc, Kind))
return false;
}
return true;
@@ -1889,11 +2018,11 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
IfStmt *If = cast<IfStmt>(S);
if (!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getThen(), ReturnStmts,
- Cxx1yLoc, Cxx2aLoc))
+ Cxx1yLoc, Cxx2aLoc, Kind))
return false;
if (If->getElse() &&
!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getElse(), ReturnStmts,
- Cxx1yLoc, Cxx2aLoc))
+ Cxx1yLoc, Cxx2aLoc, Kind))
return false;
return true;
}
@@ -1912,7 +2041,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
for (Stmt *SubStmt : S->children())
if (SubStmt &&
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
- Cxx1yLoc, Cxx2aLoc))
+ Cxx1yLoc, Cxx2aLoc, Kind))
return false;
return true;
@@ -1927,17 +2056,20 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
for (Stmt *SubStmt : S->children())
if (SubStmt &&
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
- Cxx1yLoc, Cxx2aLoc))
+ Cxx1yLoc, Cxx2aLoc, Kind))
return false;
return true;
+ case Stmt::GCCAsmStmtClass:
+ case Stmt::MSAsmStmtClass:
+ // C++2a allows inline assembly statements.
case Stmt::CXXTryStmtClass:
if (Cxx2aLoc.isInvalid())
Cxx2aLoc = S->getBeginLoc();
for (Stmt *SubStmt : S->children()) {
if (SubStmt &&
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
- Cxx1yLoc, Cxx2aLoc))
+ Cxx1yLoc, Cxx2aLoc, Kind))
return false;
}
return true;
@@ -1947,7 +2079,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
// try block check).
if (!CheckConstexprFunctionStmt(SemaRef, Dcl,
cast<CXXCatchStmt>(S)->getHandlerBlock(),
- ReturnStmts, Cxx1yLoc, Cxx2aLoc))
+ ReturnStmts, Cxx1yLoc, Cxx2aLoc, Kind))
return false;
return true;
@@ -1961,16 +2093,21 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
return true;
}
- SemaRef.Diag(S->getBeginLoc(), diag::err_constexpr_body_invalid_stmt)
- << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ SemaRef.Diag(S->getBeginLoc(), diag::err_constexpr_body_invalid_stmt)
+ << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
+ }
return false;
}
/// Check the body for the given constexpr function declaration only contains
/// the permitted types of statement. C++11 [dcl.constexpr]p3,p4.
///
-/// \return true if the body is OK, false if we have diagnosed a problem.
-bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
+/// \return true if the body is OK, false if we have found or diagnosed a
+/// problem.
+static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
+ Stmt *Body,
+ Sema::CheckConstexprKind Kind) {
SmallVector<SourceLocation, 4> ReturnStmts;
if (isa<CXXTryStmt>(Body)) {
@@ -1986,11 +2123,20 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
//
// This restriction is lifted in C++2a, as long as inner statements also
// apply the general constexpr rules.
- Diag(Body->getBeginLoc(),
- !getLangOpts().CPlusPlus2a
- ? diag::ext_constexpr_function_try_block_cxx2a
- : diag::warn_cxx17_compat_constexpr_function_try_block)
- << isa<CXXConstructorDecl>(Dcl);
+ switch (Kind) {
+ case Sema::CheckConstexprKind::CheckValid:
+ if (!SemaRef.getLangOpts().CPlusPlus2a)
+ return false;
+ break;
+
+ case Sema::CheckConstexprKind::Diagnose:
+ SemaRef.Diag(Body->getBeginLoc(),
+ !SemaRef.getLangOpts().CPlusPlus2a
+ ? diag::ext_constexpr_function_try_block_cxx2a
+ : diag::warn_cxx17_compat_constexpr_function_try_block)
+ << isa<CXXConstructorDecl>(Dcl);
+ break;
+ }
}
// - its function-body shall be [...] a compound-statement that contains only
@@ -2001,23 +2147,30 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
SourceLocation Cxx1yLoc, Cxx2aLoc;
for (Stmt *SubStmt : Body->children()) {
if (SubStmt &&
- !CheckConstexprFunctionStmt(*this, Dcl, SubStmt, ReturnStmts,
- Cxx1yLoc, Cxx2aLoc))
+ !CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
+ Cxx1yLoc, Cxx2aLoc, Kind))
return false;
}
- if (Cxx2aLoc.isValid())
- Diag(Cxx2aLoc,
- getLangOpts().CPlusPlus2a
+ if (Kind == Sema::CheckConstexprKind::CheckValid) {
+ // If this is only valid as an extension, report that we don't satisfy the
+ // constraints of the current language.
+ if ((Cxx2aLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus2a) ||
+ (Cxx1yLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus17))
+ return false;
+ } else if (Cxx2aLoc.isValid()) {
+ SemaRef.Diag(Cxx2aLoc,
+ SemaRef.getLangOpts().CPlusPlus2a
? diag::warn_cxx17_compat_constexpr_body_invalid_stmt
: diag::ext_constexpr_body_invalid_stmt_cxx2a)
<< isa<CXXConstructorDecl>(Dcl);
- if (Cxx1yLoc.isValid())
- Diag(Cxx1yLoc,
- getLangOpts().CPlusPlus14
+ } else if (Cxx1yLoc.isValid()) {
+ SemaRef.Diag(Cxx1yLoc,
+ SemaRef.getLangOpts().CPlusPlus14
? diag::warn_cxx11_compat_constexpr_body_invalid_stmt
: diag::ext_constexpr_body_invalid_stmt)
<< isa<CXXConstructorDecl>(Dcl);
+ }
if (const CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(Dcl)) {
@@ -2031,8 +2184,15 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
if (RD->isUnion()) {
if (Constructor->getNumCtorInitializers() == 0 &&
RD->hasVariantMembers()) {
- Diag(Dcl->getLocation(), diag::err_constexpr_union_ctor_no_init);
- return false;
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ SemaRef.Diag(
+ Dcl->getLocation(),
+ SemaRef.getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_constexpr_union_ctor_no_init
+ : diag::ext_constexpr_union_ctor_no_init);
+ } else if (!SemaRef.getLangOpts().CPlusPlus2a) {
+ return false;
+ }
}
} else if (!Constructor->isDependentContext() &&
!Constructor->isDelegatingConstructor()) {
@@ -2068,9 +2228,9 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
bool Diagnosed = false;
for (auto *I : RD->fields())
- CheckConstexprCtorInitializer(*this, Dcl, I, Inits, Diagnosed);
- if (Diagnosed)
- return false;
+ if (!CheckConstexprCtorInitializer(SemaRef, Dcl, I, Inits, Diagnosed,
+ Kind))
+ return false;
}
}
} else {
@@ -2079,22 +2239,45 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
// statement. We still do, unless the return type might be void, because
// otherwise if there's no return statement, the function cannot
// be used in a core constant expression.
- bool OK = getLangOpts().CPlusPlus14 &&
+ bool OK = SemaRef.getLangOpts().CPlusPlus14 &&
(Dcl->getReturnType()->isVoidType() ||
Dcl->getReturnType()->isDependentType());
- Diag(Dcl->getLocation(),
- OK ? diag::warn_cxx11_compat_constexpr_body_no_return
- : diag::err_constexpr_body_no_return)
- << Dcl->isConsteval();
- if (!OK)
- return false;
+ switch (Kind) {
+ case Sema::CheckConstexprKind::Diagnose:
+ SemaRef.Diag(Dcl->getLocation(),
+ OK ? diag::warn_cxx11_compat_constexpr_body_no_return
+ : diag::err_constexpr_body_no_return)
+ << Dcl->isConsteval();
+ if (!OK)
+ return false;
+ break;
+
+ case Sema::CheckConstexprKind::CheckValid:
+ // The formal requirements don't include this rule in C++14, even
+ // though the "must be able to produce a constant expression" rules
+ // still imply it in some cases.
+ if (!SemaRef.getLangOpts().CPlusPlus14)
+ return false;
+ break;
+ }
} else if (ReturnStmts.size() > 1) {
- Diag(ReturnStmts.back(),
- getLangOpts().CPlusPlus14
- ? diag::warn_cxx11_compat_constexpr_body_multiple_return
- : diag::ext_constexpr_body_multiple_return);
- for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I)
- Diag(ReturnStmts[I], diag::note_constexpr_body_previous_return);
+ switch (Kind) {
+ case Sema::CheckConstexprKind::Diagnose:
+ SemaRef.Diag(
+ ReturnStmts.back(),
+ SemaRef.getLangOpts().CPlusPlus14
+ ? diag::warn_cxx11_compat_constexpr_body_multiple_return
+ : diag::ext_constexpr_body_multiple_return);
+ for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I)
+ SemaRef.Diag(ReturnStmts[I],
+ diag::note_constexpr_body_previous_return);
+ break;
+
+ case Sema::CheckConstexprKind::CheckValid:
+ if (!SemaRef.getLangOpts().CPlusPlus14)
+ return false;
+ break;
+ }
}
}
@@ -2108,12 +2291,17 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
// C++11 [dcl.constexpr]p4:
// - every constructor involved in initializing non-static data members and
// base class sub-objects shall be a constexpr constructor.
+ //
+ // Note that this rule is distinct from the "requirements for a constexpr
+ // function", so is not checked in CheckValid mode.
SmallVector<PartialDiagnosticAt, 8> Diags;
- if (!Expr::isPotentialConstantExpr(Dcl, Diags)) {
- Diag(Dcl->getLocation(), diag::ext_constexpr_function_never_constant_expr)
- << isa<CXXConstructorDecl>(Dcl);
+ if (Kind == Sema::CheckConstexprKind::Diagnose &&
+ !Expr::isPotentialConstantExpr(Dcl, Diags)) {
+ SemaRef.Diag(Dcl->getLocation(),
+ diag::ext_constexpr_function_never_constant_expr)
+ << isa<CXXConstructorDecl>(Dcl);
for (size_t I = 0, N = Diags.size(); I != N; ++I)
- Diag(Diags[I].first, Diags[I].second);
+ SemaRef.Diag(Diags[I].first, Diags[I].second);
// Don't return false here: we allow this for compatibility in
// system headers.
}
@@ -2298,7 +2486,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
}
// If the base class is polymorphic or isn't empty, the new one is/isn't, too.
- RecordDecl *BaseDecl = BaseType->getAs<RecordType>()->getDecl();
+ RecordDecl *BaseDecl = BaseType->castAs<RecordType>()->getDecl();
assert(BaseDecl && "Record type has no declaration");
BaseDecl = BaseDecl->getDefinition();
assert(BaseDecl && "Base type is not incomplete, but has no definition");
@@ -2381,7 +2569,7 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
Diag(AL.getLoc(), AL.getKind() == ParsedAttr::UnknownAttribute
? (unsigned)diag::warn_unknown_attribute_ignored
: (unsigned)diag::err_base_specifier_attribute)
- << AL.getName();
+ << AL;
}
TypeSourceInfo *TInfo = nullptr;
@@ -3225,10 +3413,12 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
}
if (VS.isOverrideSpecified())
- Member->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context, 0));
+ Member->addAttr(OverrideAttr::Create(Context, VS.getOverrideLoc(),
+ AttributeCommonInfo::AS_Keyword));
if (VS.isFinalSpecified())
- Member->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context,
- VS.isFinalSpelledSealed()));
+ Member->addAttr(FinalAttr::Create(
+ Context, VS.getFinalLoc(), AttributeCommonInfo::AS_Keyword,
+ static_cast<FinalAttr::Spelling>(VS.isFinalSpelledSealed())));
if (VS.getLastLocation().isValid()) {
// Update the end location of a method that has a virt-specifiers.
@@ -3826,7 +4016,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<MemInitializerValidatorCCC>(*this);
+ return std::make_unique<MemInitializerValidatorCCC>(*this);
}
private:
@@ -5801,14 +5991,10 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
TSK != TSK_ExplicitInstantiationDefinition) {
if (ClassExported) {
NewAttr = ::new (getASTContext())
- DLLExportStaticLocalAttr(ClassAttr->getRange(),
- getASTContext(),
- ClassAttr->getSpellingListIndex());
+ DLLExportStaticLocalAttr(getASTContext(), *ClassAttr);
} else {
NewAttr = ::new (getASTContext())
- DLLImportStaticLocalAttr(ClassAttr->getRange(),
- getASTContext(),
- ClassAttr->getSpellingListIndex());
+ DLLImportStaticLocalAttr(getASTContext(), *ClassAttr);
}
} else {
NewAttr = cast<InheritableAttr>(ClassAttr->clone(getASTContext()));
@@ -6117,6 +6303,22 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
}
}
+ // Warn if the class has a final destructor but is not itself marked final.
+ if (!Record->hasAttr<FinalAttr>()) {
+ if (const CXXDestructorDecl *dtor = Record->getDestructor()) {
+ if (const FinalAttr *FA = dtor->getAttr<FinalAttr>()) {
+ Diag(FA->getLocation(), diag::warn_final_dtor_non_final_class)
+ << FA->isSpelledAsSealed()
+ << FixItHint::CreateInsertion(
+ getLocForEndOfToken(Record->getLocation()),
+ (FA->isSpelledAsSealed() ? " sealed" : " final"));
+ Diag(Record->getLocation(),
+ diag::note_final_dtor_non_final_class_silence)
+ << Context.getRecordType(Record) << FA->isSpelledAsSealed();
+ }
+ }
+ }
+
// See if trivial_abi has to be dropped.
if (Record->hasAttr<TrivialABIAttr>())
checkIllFormedTrivialABIStruct(*Record);
@@ -6165,10 +6367,16 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
M->dropAttr<DLLExportAttr>();
if (M->hasAttr<DLLExportAttr>()) {
- DefineImplicitSpecialMember(*this, M, M->getLocation());
- ActOnFinishInlineFunctionDef(M);
+ // Define after any fields with in-class initializers have been parsed.
+ DelayedDllExportMemberFunctions.push_back(M);
}
}
+
+ // Define defaulted constexpr virtual functions that override a base class
+ // function right away.
+ // FIXME: We can defer doing this until the vtable is marked as used.
+ if (M->isDefaulted() && M->isConstexpr() && M->size_overridden_methods())
+ DefineImplicitSpecialMember(*this, M, M->getLocation());
};
bool HasMethodWithOverrideControl = false,
@@ -6382,6 +6590,8 @@ specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
if (CSM == Sema::CXXDefaultConstructor)
return ClassDecl->hasConstexprDefaultConstructor();
+ if (CSM == Sema::CXXDestructor)
+ return ClassDecl->hasConstexprDestructor();
Sema::SpecialMemberOverloadResult SMOR =
lookupCallFromSpecialMember(S, ClassDecl, CSM, Quals, ConstRHS);
@@ -6430,6 +6640,8 @@ static bool defaultedSpecialMemberIsConstexpr(
break;
case Sema::CXXDestructor:
+ return ClassDecl->defaultedDestructorIsConstexpr();
+
case Sema::CXXInvalid:
return false;
}
@@ -6682,13 +6894,14 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// Do not apply this rule to members of class templates, since core issue 1358
// makes such functions always instantiate to constexpr functions. For
// functions which cannot be constexpr (for non-constructors in C++11 and for
- // destructors in C++1y), this is checked elsewhere.
+ // destructors in C++14 and C++17), this is checked elsewhere.
//
// FIXME: This should not apply if the member is deleted.
bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM,
HasConstParam);
- if ((getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(MD)
- : isa<CXXConstructorDecl>(MD)) &&
+ if ((getLangOpts().CPlusPlus2a ||
+ (getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(MD)
+ : isa<CXXConstructorDecl>(MD))) &&
MD->isConstexpr() && !Constexpr &&
MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
Diag(MD->getBeginLoc(), MD->isConsteval()
@@ -7798,7 +8011,7 @@ public:
/// to be used with CXXRecordDecl::lookupInBases().
bool operator()(const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
RecordDecl *BaseRecord =
- Specifier->getType()->getAs<RecordType>()->getDecl();
+ Specifier->getType()->castAs<RecordType>()->getDecl();
DeclarationName Name = Method->getDeclName();
assert(Name.getNameKind() == DeclarationName::Identifier);
@@ -7966,8 +8179,7 @@ void Sema::ActOnFinishCXXMemberSpecification(
if (AL.getKind() != ParsedAttr::AT_Visibility)
continue;
AL.setInvalid();
- Diag(AL.getLoc(), diag::warn_attribute_after_definition_ignored)
- << AL.getName();
+ Diag(AL.getLoc(), diag::warn_attribute_after_definition_ignored) << AL;
}
ActOnFields(S, RLoc, TagDecl, llvm::makeArrayRef(
@@ -9386,7 +9598,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<NamespaceValidatorCCC>(*this);
+ return std::make_unique<NamespaceValidatorCCC>(*this);
}
};
@@ -9882,7 +10094,8 @@ static CXXBaseSpecifier *findDirectBaseWithType(CXXRecordDecl *Derived,
QualType DesiredBase,
bool &AnyDependentBases) {
// Check whether the named type is a direct base class.
- CanQualType CanonicalDesiredBase = DesiredBase->getCanonicalTypeUnqualified();
+ CanQualType CanonicalDesiredBase = DesiredBase->getCanonicalTypeUnqualified()
+ .getUnqualifiedType();
for (auto &Base : Derived->bases()) {
CanQualType BaseType = Base.getType()->getCanonicalTypeUnqualified();
if (CanonicalDesiredBase == BaseType)
@@ -9965,7 +10178,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<UsingValidatorCCC>(*this);
+ return std::make_unique<UsingValidatorCCC>(*this);
}
private:
@@ -11311,6 +11524,10 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
if (DSM.isAlreadyBeingDeclared())
return nullptr;
+ bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl,
+ CXXDestructor,
+ false);
+
// Create the actual destructor declaration.
CanQualType ClassType
= Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
@@ -11318,10 +11535,11 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
DeclarationName Name
= Context.DeclarationNames.getCXXDestructorName(ClassType);
DeclarationNameInfo NameInfo(Name, ClassLoc);
- CXXDestructorDecl *Destructor
- = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
- QualType(), nullptr, /*isInline=*/true,
- /*isImplicitlyDeclared=*/true);
+ CXXDestructorDecl *Destructor =
+ CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
+ QualType(), nullptr, /*isInline=*/true,
+ /*isImplicitlyDeclared=*/true,
+ Constexpr ? CSK_constexpr : CSK_unspecified);
Destructor->setAccess(AS_public);
Destructor->setDefaulted();
@@ -11419,6 +11637,21 @@ void Sema::ActOnFinishCXXMemberDecls() {
void Sema::ActOnFinishCXXNonNestedClass(Decl *D) {
referenceDLLExportedClassMethods();
+
+ if (!DelayedDllExportMemberFunctions.empty()) {
+ SmallVector<CXXMethodDecl*, 4> WorkList;
+ std::swap(DelayedDllExportMemberFunctions, WorkList);
+ for (CXXMethodDecl *M : WorkList) {
+ DefineImplicitSpecialMember(*this, M, M->getLocation());
+
+ // Pass the method to the consumer to get emitted. This is not necessary
+ // for explicit instantiation definitions, as they will get emitted
+ // anyway.
+ if (M->getParent()->getTemplateSpecializationKind() !=
+ TSK_ExplicitInstantiationDefinition)
+ ActOnFinishInlineFunctionDef(M);
+ }
+ }
}
void Sema::referenceDLLExportedClassMethods() {
@@ -11619,7 +11852,8 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T,
const Type *E = T->getBaseElementTypeUnsafe();
bool NeedsCollectableMemCpy =
- E->isRecordType() && E->getAs<RecordType>()->getDecl()->hasObjectMember();
+ E->isRecordType() &&
+ E->castAs<RecordType>()->getDecl()->hasObjectMember();
// Create a reference to the __builtin_objc_memmove_collectable function
StringRef MemCpyName = NeedsCollectableMemCpy ?
@@ -13172,6 +13406,20 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
}
if (Destructor->isTrivial()) return;
+
+ // If the destructor is constexpr, check whether the variable has constant
+ // destruction now.
+ if (Destructor->isConstexpr() && VD->getInit() &&
+ !VD->getInit()->isValueDependent() && VD->evaluateValue()) {
+ SmallVector<PartialDiagnosticAt, 8> Notes;
+ if (!VD->evaluateDestruction(Notes) && VD->isConstexpr()) {
+ Diag(VD->getLocation(),
+ diag::err_constexpr_var_requires_const_destruction) << VD;
+ for (unsigned I = 0, N = Notes.size(); I != N; ++I)
+ Diag(Notes[I].first, Notes[I].second);
+ }
+ }
+
if (!VD->hasGlobalStorage()) return;
// Emit warning for non-trivial dtor in global scope (a real global,
@@ -13762,6 +14010,10 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc,
Language = LinkageSpecDecl::lang_c;
else if (Lang == "C++")
Language = LinkageSpecDecl::lang_cxx;
+ else if (Lang == "C++11")
+ Language = LinkageSpecDecl::lang_cxx_11;
+ else if (Lang == "C++14")
+ Language = LinkageSpecDecl::lang_cxx_14;
else {
Diag(LangStr->getExprLoc(), diag::err_language_linkage_spec_unknown)
<< LangStr->getSourceRange();
@@ -14014,8 +14266,17 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
if (Converted.isInvalid())
Failed = true;
+ ExprResult FullAssertExpr =
+ ActOnFinishFullExpr(Converted.get(), StaticAssertLoc,
+ /*DiscardedValue*/ false,
+ /*IsConstexpr*/ true);
+ if (FullAssertExpr.isInvalid())
+ Failed = true;
+ else
+ AssertExpr = FullAssertExpr.get();
+
llvm::APSInt Cond;
- if (!Failed && VerifyIntegerConstantExpression(Converted.get(), &Cond,
+ if (!Failed && VerifyIntegerConstantExpression(AssertExpr, &Cond,
diag::err_static_assert_expression_is_not_constant,
/*AllowFold=*/false).isInvalid())
Failed = true;
@@ -14041,16 +14302,16 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
}
Failed = true;
}
+ } else {
+ ExprResult FullAssertExpr = ActOnFinishFullExpr(AssertExpr, StaticAssertLoc,
+ /*DiscardedValue*/false,
+ /*IsConstexpr*/true);
+ if (FullAssertExpr.isInvalid())
+ Failed = true;
+ else
+ AssertExpr = FullAssertExpr.get();
}
- ExprResult FullAssertExpr = ActOnFinishFullExpr(AssertExpr, StaticAssertLoc,
- /*DiscardedValue*/false,
- /*IsConstexpr*/true);
- if (FullAssertExpr.isInvalid())
- Failed = true;
- else
- AssertExpr = FullAssertExpr.get();
-
Decl *Decl = StaticAssertDecl::Create(Context, CurContext, StaticAssertLoc,
AssertExpr, AssertMessage, RParenLoc,
Failed);
@@ -15282,8 +15543,8 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
return;
for (const auto &I : RD->bases()) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const auto *Base =
+ cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
if (Base->getNumVBases() == 0)
continue;
MarkVirtualMembersReferenced(Loc, Base);
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index e629837eb71d..db594bbd21dd 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -512,7 +512,7 @@ class ObjCInterfaceValidatorCCC final : public CorrectionCandidateCallback {
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<ObjCInterfaceValidatorCCC>(*this);
+ return std::make_unique<ObjCInterfaceValidatorCCC>(*this);
}
private:
@@ -586,7 +586,7 @@ ActOnSuperClassOfClassInterface(Scope *S,
dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) {
QualType T = TDecl->getUnderlyingType();
if (T->isObjCObjectType()) {
- if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) {
+ if (NamedDecl *IDecl = T->castAs<ObjCObjectType>()->getInterface()) {
SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl);
SuperClassType = Context.getTypeDeclType(TDecl);
@@ -1151,7 +1151,7 @@ Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc,
dyn_cast_or_null<TypedefNameDecl>(CDeclU)) {
QualType T = TDecl->getUnderlyingType();
if (T->isObjCObjectType()) {
- if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) {
+ if (NamedDecl *IDecl = T->castAs<ObjCObjectType>()->getInterface()) {
ClassName = IDecl->getIdentifier();
CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation,
LookupOrdinaryName,
@@ -1387,7 +1387,7 @@ class ObjCTypeArgOrProtocolValidatorCCC final
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<ObjCTypeArgOrProtocolValidatorCCC>(*this);
+ return std::make_unique<ObjCTypeArgOrProtocolValidatorCCC>(*this);
}
};
} // end anonymous namespace
@@ -2275,9 +2275,7 @@ static bool isObjCTypeSubstitutable(ASTContext &Context,
// stricter definition so it is not substitutable for id<A>.
if (B->isObjCQualifiedIdType()) {
return A->isObjCQualifiedIdType() &&
- Context.ObjCQualifiedIdTypesAreCompatible(QualType(A, 0),
- QualType(B,0),
- false);
+ Context.ObjCQualifiedIdTypesAreCompatible(A, B, false);
}
/*
@@ -4878,7 +4876,7 @@ VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType T,
} else if (!T->isObjCObjectPointerType()) {
Invalid = true;
Diag(IdLoc, diag::err_catch_param_not_objc_type);
- } else if (!T->getAs<ObjCObjectPointerType>()->getInterfaceType()) {
+ } else if (!T->castAs<ObjCObjectPointerType>()->getInterfaceType()) {
Invalid = true;
Diag(IdLoc, diag::err_catch_param_not_objc_type);
}
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 9fd924a8cad0..c1abf099e9f2 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -149,12 +149,12 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) {
// In Microsoft mode, downgrade this to a warning.
unsigned DiagID = diag::err_incomplete_in_exception_spec;
bool ReturnValueOnError = true;
- if (getLangOpts().MicrosoftExt) {
+ if (getLangOpts().MSVCCompat) {
DiagID = diag::ext_incomplete_in_exception_spec;
ReturnValueOnError = false;
}
if (!(PointeeT->isRecordType() &&
- PointeeT->getAs<RecordType>()->isBeingDefined()) &&
+ PointeeT->castAs<RecordType>()->isBeingDefined()) &&
RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range))
return ReturnValueOnError;
@@ -263,8 +263,7 @@ static bool hasImplicitExceptionSpec(FunctionDecl *Decl) {
if (!Decl->getTypeSourceInfo())
return isa<CXXDestructorDecl>(Decl);
- const FunctionProtoType *Ty =
- Decl->getTypeSourceInfo()->getType()->getAs<FunctionProtoType>();
+ auto *Ty = Decl->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>();
return !Ty->hasExceptionSpec();
}
@@ -282,7 +281,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
unsigned DiagID = diag::err_mismatched_exception_spec;
bool ReturnValueOnError = true;
- if (getLangOpts().MicrosoftExt) {
+ if (getLangOpts().MSVCCompat) {
DiagID = diag::ext_mismatched_exception_spec;
ReturnValueOnError = false;
}
@@ -371,7 +370,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
NewProto->getExtProtoInfo().withExceptionSpec(ESI)));
}
- if (getLangOpts().MicrosoftExt && ESI.Type != EST_DependentNoexcept) {
+ if (getLangOpts().MSVCCompat && ESI.Type != EST_DependentNoexcept) {
// Allow missing exception specifications in redeclarations as an extension.
DiagID = diag::ext_ms_missing_exception_specification;
ReturnValueOnError = false;
@@ -473,14 +472,14 @@ bool Sema::CheckEquivalentExceptionSpec(
return false;
unsigned DiagID = diag::err_mismatched_exception_spec;
- if (getLangOpts().MicrosoftExt)
+ if (getLangOpts().MSVCCompat)
DiagID = diag::ext_mismatched_exception_spec;
bool Result = CheckEquivalentExceptionSpecImpl(
*this, PDiag(DiagID), PDiag(diag::note_previous_declaration),
Old, OldLoc, New, NewLoc);
// In Microsoft mode, mismatching exception specifications just cause a warning.
- if (getLangOpts().MicrosoftExt)
+ if (getLangOpts().MSVCCompat)
return false;
return Result;
}
@@ -959,15 +958,15 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
}
unsigned DiagID = diag::err_override_exception_spec;
- if (getLangOpts().MicrosoftExt)
+ if (getLangOpts().MSVCCompat)
DiagID = diag::ext_override_exception_spec;
return CheckExceptionSpecSubset(PDiag(DiagID),
PDiag(diag::err_deep_exception_specs_differ),
PDiag(diag::note_overridden_virtual_function),
PDiag(diag::ext_override_exception_spec),
- Old->getType()->getAs<FunctionProtoType>(),
+ Old->getType()->castAs<FunctionProtoType>(),
Old->getLocation(),
- New->getType()->getAs<FunctionProtoType>(),
+ New->getType()->castAs<FunctionProtoType>(),
New->getLocation());
}
@@ -1201,6 +1200,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::CoyieldExprClass:
case Expr::CXXConstCastExprClass:
case Expr::CXXReinterpretCastExprClass:
+ case Expr::CXXRewrittenBinaryOperatorClass:
case Expr::BuiltinBitCastExprClass:
case Expr::CXXStdInitializerListExprClass:
case Expr::DesignatedInitExprClass:
@@ -1314,6 +1314,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::SizeOfPackExprClass:
case Expr::StringLiteralClass:
case Expr::SourceLocExprClass:
+ case Expr::ConceptSpecializationExprClass:
// These expressions can never throw.
return CT_Cannot;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index d8869ffe945a..e41cd5b6653a 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1990,16 +1990,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
R.clear();
}
- // In Microsoft mode, if we are performing lookup from within a friend
- // function definition declared at class scope then we must set
- // DC to the lexical parent to be able to search into the parent
- // class.
- if (getLangOpts().MSVCCompat && isa<FunctionDecl>(DC) &&
- cast<FunctionDecl>(DC)->getFriendObjectKind() &&
- DC->getLexicalParent()->isRecord())
- DC = DC->getLexicalParent();
- else
- DC = DC->getParent();
+ DC = DC->getLookupParent();
}
// We didn't find anything, so try to correct for a typo.
@@ -2491,23 +2482,20 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr(
return BuildDeclarationNameExpr(SS, R, /* ADL */ false);
}
-/// LookupInObjCMethod - The parser has read a name in, and Sema has
-/// detected that we're currently inside an ObjC method. Perform some
-/// additional lookup.
+/// The parser has read a name in, and Sema has detected that we're currently
+/// inside an ObjC method. Perform some additional checks and determine if we
+/// should form a reference to an ivar.
///
/// Ideally, most of this would be done by lookup, but there's
/// actually quite a lot of extra work involved.
-///
-/// Returns a null sentinel to indicate trivial success.
-ExprResult
-Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
- IdentifierInfo *II, bool AllowBuiltinCreation) {
+DeclResult Sema::LookupIvarInObjCMethod(LookupResult &Lookup, Scope *S,
+ IdentifierInfo *II) {
SourceLocation Loc = Lookup.getNameLoc();
ObjCMethodDecl *CurMethod = getCurMethodDecl();
// Check for error condition which is already reported.
if (!CurMethod)
- return ExprError();
+ return DeclResult(true);
// There are two cases to handle here. 1) scoped lookup could have failed,
// in which case we should look for an ivar. 2) scoped lookup could have
@@ -2535,18 +2523,10 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
ObjCIvarDecl *IV = nullptr;
if (IFace && (IV = IFace->lookupInstanceVariable(II, ClassDeclared))) {
// Diagnose using an ivar in a class method.
- if (IsClassMethod)
- return ExprError(Diag(Loc, diag::err_ivar_use_in_class_method)
- << IV->getDeclName());
-
- // If we're referencing an invalid decl, just return this as a silent
- // error node. The error diagnostic was already emitted on the decl.
- if (IV->isInvalidDecl())
- return ExprError();
-
- // Check if referencing a field with __attribute__((deprecated)).
- if (DiagnoseUseOfDecl(IV, Loc))
- return ExprError();
+ if (IsClassMethod) {
+ Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName();
+ return DeclResult(true);
+ }
// Diagnose the use of an ivar outside of the declaring class.
if (IV->getAccessControl() == ObjCIvarDecl::Private &&
@@ -2554,46 +2534,8 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
!getLangOpts().DebuggerSupport)
Diag(Loc, diag::err_private_ivar_access) << IV->getDeclName();
- // FIXME: This should use a new expr for a direct reference, don't
- // turn this into Self->ivar, just return a BareIVarExpr or something.
- IdentifierInfo &II = Context.Idents.get("self");
- UnqualifiedId SelfName;
- SelfName.setIdentifier(&II, SourceLocation());
- SelfName.setKind(UnqualifiedIdKind::IK_ImplicitSelfParam);
- CXXScopeSpec SelfScopeSpec;
- SourceLocation TemplateKWLoc;
- ExprResult SelfExpr =
- ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc, SelfName,
- /*HasTrailingLParen=*/false,
- /*IsAddressOfOperand=*/false);
- if (SelfExpr.isInvalid())
- return ExprError();
-
- SelfExpr = DefaultLvalueConversion(SelfExpr.get());
- if (SelfExpr.isInvalid())
- return ExprError();
-
- MarkAnyDeclReferenced(Loc, IV, true);
-
- ObjCMethodFamily MF = CurMethod->getMethodFamily();
- if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize &&
- !IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV))
- Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName();
-
- ObjCIvarRefExpr *Result = new (Context)
- ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc,
- IV->getLocation(), SelfExpr.get(), true, true);
-
- if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
- if (!isUnevaluatedContext() &&
- !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
- getCurFunction()->recordUseOfWeak(Result);
- }
- if (getLangOpts().ObjCAutoRefCount)
- if (const BlockDecl *BD = CurContext->getInnermostBlockDecl())
- ImplicitlyRetainedSelfLocs.push_back({Loc, BD});
-
- return Result;
+ // Success.
+ return IV;
}
} else if (CurMethod->isInstanceMethod()) {
// We should warn if a local variable hides an ivar.
@@ -2608,25 +2550,97 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
} else if (Lookup.isSingleResult() &&
Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()) {
// If accessing a stand-alone ivar in a class method, this is an error.
- if (const ObjCIvarDecl *IV = dyn_cast<ObjCIvarDecl>(Lookup.getFoundDecl()))
- return ExprError(Diag(Loc, diag::err_ivar_use_in_class_method)
- << IV->getDeclName());
- }
-
- if (Lookup.empty() && II && AllowBuiltinCreation) {
- // FIXME. Consolidate this with similar code in LookupName.
- if (unsigned BuiltinID = II->getBuiltinID()) {
- if (!(getLangOpts().CPlusPlus &&
- Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))) {
- NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
- S, Lookup.isForRedeclaration(),
- Lookup.getNameLoc());
- if (D) Lookup.addDecl(D);
- }
+ if (const ObjCIvarDecl *IV =
+ dyn_cast<ObjCIvarDecl>(Lookup.getFoundDecl())) {
+ Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName();
+ return DeclResult(true);
}
}
+
+ // Didn't encounter an error, didn't find an ivar.
+ return DeclResult(false);
+}
+
+ExprResult Sema::BuildIvarRefExpr(Scope *S, SourceLocation Loc,
+ ObjCIvarDecl *IV) {
+ ObjCMethodDecl *CurMethod = getCurMethodDecl();
+ assert(CurMethod && CurMethod->isInstanceMethod() &&
+ "should not reference ivar from this context");
+
+ ObjCInterfaceDecl *IFace = CurMethod->getClassInterface();
+ assert(IFace && "should not reference ivar from this context");
+
+ // If we're referencing an invalid decl, just return this as a silent
+ // error node. The error diagnostic was already emitted on the decl.
+ if (IV->isInvalidDecl())
+ return ExprError();
+
+ // Check if referencing a field with __attribute__((deprecated)).
+ if (DiagnoseUseOfDecl(IV, Loc))
+ return ExprError();
+
+ // FIXME: This should use a new expr for a direct reference, don't
+ // turn this into Self->ivar, just return a BareIVarExpr or something.
+ IdentifierInfo &II = Context.Idents.get("self");
+ UnqualifiedId SelfName;
+ SelfName.setIdentifier(&II, SourceLocation());
+ SelfName.setKind(UnqualifiedIdKind::IK_ImplicitSelfParam);
+ CXXScopeSpec SelfScopeSpec;
+ SourceLocation TemplateKWLoc;
+ ExprResult SelfExpr =
+ ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc, SelfName,
+ /*HasTrailingLParen=*/false,
+ /*IsAddressOfOperand=*/false);
+ if (SelfExpr.isInvalid())
+ return ExprError();
+
+ SelfExpr = DefaultLvalueConversion(SelfExpr.get());
+ if (SelfExpr.isInvalid())
+ return ExprError();
+
+ MarkAnyDeclReferenced(Loc, IV, true);
+
+ ObjCMethodFamily MF = CurMethod->getMethodFamily();
+ if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize &&
+ !IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV))
+ Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName();
+
+ ObjCIvarRefExpr *Result = new (Context)
+ ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc,
+ IV->getLocation(), SelfExpr.get(), true, true);
+
+ if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
+ if (!isUnevaluatedContext() &&
+ !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
+ getCurFunction()->recordUseOfWeak(Result);
+ }
+ if (getLangOpts().ObjCAutoRefCount)
+ if (const BlockDecl *BD = CurContext->getInnermostBlockDecl())
+ ImplicitlyRetainedSelfLocs.push_back({Loc, BD});
+
+ return Result;
+}
+
+/// The parser has read a name in, and Sema has detected that we're currently
+/// inside an ObjC method. Perform some additional checks and determine if we
+/// should form a reference to an ivar. If so, build an expression referencing
+/// that ivar.
+ExprResult
+Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
+ IdentifierInfo *II, bool AllowBuiltinCreation) {
+ // FIXME: Integrate this lookup step into LookupParsedName.
+ DeclResult Ivar = LookupIvarInObjCMethod(Lookup, S, II);
+ if (Ivar.isInvalid())
+ return ExprError();
+ if (Ivar.isUsable())
+ return BuildIvarRefExpr(S, Lookup.getNameLoc(),
+ cast<ObjCIvarDecl>(Ivar.get()));
+
+ if (Lookup.empty() && II && AllowBuiltinCreation)
+ LookupBuiltin(Lookup);
+
// Sentinel value saying that we didn't do anything special.
- return ExprResult((Expr *)nullptr);
+ return ExprResult(false);
}
/// Cast a base object to a member's actual type.
@@ -3216,13 +3230,15 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
SmallString<32> RawChars;
ConvertUTF8ToWideString(Context.getTypeSizeInChars(ResTy).getQuantity(),
Str, RawChars);
- ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal,
+ ResTy = Context.getConstantArrayType(ResTy, LengthI, nullptr,
+ ArrayType::Normal,
/*IndexTypeQuals*/ 0);
SL = StringLiteral::Create(Context, RawChars, StringLiteral::Wide,
/*Pascal*/ false, ResTy, Loc);
} else {
ResTy = Context.adjustStringLiteralBaseType(Context.CharTy.withConst());
- ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal,
+ ResTy = Context.getConstantArrayType(ResTy, LengthI, nullptr,
+ ArrayType::Normal,
/*IndexTypeQuals*/ 0);
SL = StringLiteral::Create(Context, Str, StringLiteral::Ascii,
/*Pascal*/ false, ResTy, Loc);
@@ -3462,7 +3478,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
unsigned Length = Literal.getUDSuffixOffset();
QualType StrTy = Context.getConstantArrayType(
Context.adjustStringLiteralBaseType(Context.CharTy.withConst()),
- llvm::APInt(32, Length + 1), ArrayType::Normal, 0);
+ llvm::APInt(32, Length + 1), nullptr, ArrayType::Normal, 0);
Expr *Lit = StringLiteral::Create(
Context, StringRef(TokSpelling.data(), Length), StringLiteral::Ascii,
/*Pascal*/false, StrTy, &TokLoc, 1);
@@ -3808,6 +3824,16 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
QualType ExprTy = E->getType();
assert(!ExprTy->isReferenceType());
+ bool IsUnevaluatedOperand =
+ (ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf ||
+ ExprKind == UETT_PreferredAlignOf);
+ if (IsUnevaluatedOperand) {
+ ExprResult Result = CheckUnevaluatedOperand(E);
+ if (Result.isInvalid())
+ return true;
+ E = Result.get();
+ }
+
if (ExprKind == UETT_VecStep)
return CheckVecStepTraitOperandType(*this, ExprTy, E->getExprLoc(),
E->getSourceRange());
@@ -3845,9 +3871,8 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
// The operand for sizeof and alignof is in an unevaluated expression context,
// so side effects could result in unintended consequences.
- if ((ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf ||
- ExprKind == UETT_PreferredAlignOf) &&
- !inTemplateInstantiation() && E->HasSideEffects(Context, false))
+ if (IsUnevaluatedOperand && !inTemplateInstantiation() &&
+ E->HasSideEffects(Context, false))
Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context);
if (CheckObjCTraitOperandConstraints(*this, ExprTy, E->getExprLoc(),
@@ -3946,8 +3971,6 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType,
}
static bool CheckAlignOfExpr(Sema &S, Expr *E, UnaryExprOrTypeTrait ExprKind) {
- E = E->IgnoreParens();
-
// Cannot know anything else if the expression is dependent.
if (E->isTypeDependent())
return false;
@@ -3959,9 +3982,10 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E, UnaryExprOrTypeTrait ExprKind) {
}
ValueDecl *D = nullptr;
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ Expr *Inner = E->IgnoreParens();
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Inner)) {
D = DRE->getDecl();
- } else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ } else if (MemberExpr *ME = dyn_cast<MemberExpr>(Inner)) {
D = ME->getMemberDecl();
}
@@ -4026,7 +4050,7 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T,
#define NON_CANONICAL_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
T = QualType();
break;
// These types are never variably-modified.
@@ -4317,6 +4341,15 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
base = result.get();
}
+ // A comma-expression as the index is deprecated in C++2a onwards.
+ if (getLangOpts().CPlusPlus2a &&
+ ((isa<BinaryOperator>(idx) && cast<BinaryOperator>(idx)->isCommaOp()) ||
+ (isa<CXXOperatorCallExpr>(idx) &&
+ cast<CXXOperatorCallExpr>(idx)->getOperator() == OO_Comma))) {
+ Diag(idx->getExprLoc(), diag::warn_deprecated_comma_subscript)
+ << SourceRange(base->getBeginLoc(), rbLoc);
+ }
+
// Handle any non-overload placeholder types in the base and index
// expressions. We can't handle overloads here because the other
// operand might be an overloadable type, in which case the overload
@@ -4823,8 +4856,10 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
// default argument expression appears.
ContextRAII SavedContext(*this, FD);
LocalInstantiationScope Local(*this);
- Result = SubstInitializer(UninstExpr, MutiLevelArgList,
- /*DirectInit*/false);
+ runWithSufficientStackSpace(CallLoc, [&] {
+ Result = SubstInitializer(UninstExpr, MutiLevelArgList,
+ /*DirectInit*/false);
+ });
}
if (Result.isInvalid())
return true;
@@ -4935,7 +4970,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<FunctionCallCCC>(*this);
+ return std::make_unique<FunctionCallCCC>(*this);
}
private:
@@ -5296,6 +5331,11 @@ static bool isPlaceholderToRemoveAsArg(QualType type) {
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
case BuiltinType::Id:
#include "clang/Basic/OpenCLExtensionTypes.def"
+ // In practice we'll never use this, since all SVE types are sugared
+ // via TypedefTypes rather than exposed directly as BuiltinTypes.
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
#define PLACEHOLDER_TYPE(ID, SINGLETON_ID)
#define BUILTIN_TYPE(ID, SINGLETON_ID) case BuiltinType::ID:
#include "clang/AST/BuiltinTypes.def"
@@ -5366,8 +5406,8 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
QualType DeclType = FDecl->getType();
const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(DeclType);
- if (!Context.BuiltinInfo.hasPtrArgsOrResult(FDecl->getBuiltinID()) ||
- !FT || FT->isVariadic() || ArgExprs.size() != FT->getNumParams())
+ if (!Context.BuiltinInfo.hasPtrArgsOrResult(FDecl->getBuiltinID()) || !FT ||
+ ArgExprs.size() < FT->getNumParams())
return nullptr;
bool NeedsNewDecl = false;
@@ -5406,6 +5446,7 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
return nullptr;
FunctionProtoType::ExtProtoInfo EPI;
+ EPI.Variadic = FT->isVariadic();
QualType OverloadTy = Context.getFunctionType(FT->getReturnType(),
OverloadParams, EPI);
DeclContext *Parent = FDecl->getParent();
@@ -5883,7 +5924,9 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
<< FDecl << Fn->getSourceRange());
// CUDA: Kernel function must have 'void' return type
- if (!FuncT->getReturnType()->isVoidType())
+ if (!FuncT->getReturnType()->isVoidType() &&
+ !FuncT->getReturnType()->getAs<AutoType>() &&
+ !FuncT->getReturnType()->isInstantiationDependentType())
return ExprError(Diag(LParenLoc, diag::err_kern_type_not_void_return)
<< Fn->getType() << Fn->getSourceRange());
} else {
@@ -6103,6 +6146,77 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
ExprResult
Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
SourceLocation RBraceLoc) {
+ // Only produce each kind of designated initialization diagnostic once.
+ SourceLocation FirstDesignator;
+ bool DiagnosedArrayDesignator = false;
+ bool DiagnosedNestedDesignator = false;
+ bool DiagnosedMixedDesignator = false;
+
+ // Check that any designated initializers are syntactically valid in the
+ // current language mode.
+ for (unsigned I = 0, E = InitArgList.size(); I != E; ++I) {
+ if (auto *DIE = dyn_cast<DesignatedInitExpr>(InitArgList[I])) {
+ if (FirstDesignator.isInvalid())
+ FirstDesignator = DIE->getBeginLoc();
+
+ if (!getLangOpts().CPlusPlus)
+ break;
+
+ if (!DiagnosedNestedDesignator && DIE->size() > 1) {
+ DiagnosedNestedDesignator = true;
+ Diag(DIE->getBeginLoc(), diag::ext_designated_init_nested)
+ << DIE->getDesignatorsSourceRange();
+ }
+
+ for (auto &Desig : DIE->designators()) {
+ if (!Desig.isFieldDesignator() && !DiagnosedArrayDesignator) {
+ DiagnosedArrayDesignator = true;
+ Diag(Desig.getBeginLoc(), diag::ext_designated_init_array)
+ << Desig.getSourceRange();
+ }
+ }
+
+ if (!DiagnosedMixedDesignator &&
+ !isa<DesignatedInitExpr>(InitArgList[0])) {
+ DiagnosedMixedDesignator = true;
+ Diag(DIE->getBeginLoc(), diag::ext_designated_init_mixed)
+ << DIE->getSourceRange();
+ Diag(InitArgList[0]->getBeginLoc(), diag::note_designated_init_mixed)
+ << InitArgList[0]->getSourceRange();
+ }
+ } else if (getLangOpts().CPlusPlus && !DiagnosedMixedDesignator &&
+ isa<DesignatedInitExpr>(InitArgList[0])) {
+ DiagnosedMixedDesignator = true;
+ auto *DIE = cast<DesignatedInitExpr>(InitArgList[0]);
+ Diag(DIE->getBeginLoc(), diag::ext_designated_init_mixed)
+ << DIE->getSourceRange();
+ Diag(InitArgList[I]->getBeginLoc(), diag::note_designated_init_mixed)
+ << InitArgList[I]->getSourceRange();
+ }
+ }
+
+ if (FirstDesignator.isValid()) {
+ // Only diagnose designated initiaization as a C++20 extension if we didn't
+ // already diagnose use of (non-C++20) C99 designator syntax.
+ if (getLangOpts().CPlusPlus && !DiagnosedArrayDesignator &&
+ !DiagnosedNestedDesignator && !DiagnosedMixedDesignator) {
+ Diag(FirstDesignator, getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_designated_init
+ : diag::ext_cxx_designated_init);
+ } else if (!getLangOpts().CPlusPlus && !getLangOpts().C99) {
+ Diag(FirstDesignator, diag::ext_designated_init);
+ }
+ }
+
+ return BuildInitList(LBraceLoc, InitArgList, RBraceLoc);
+}
+
+ExprResult
+Sema::BuildInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
+ SourceLocation RBraceLoc) {
+ // Semantic analysis for initializers is done by ActOnDeclarator() and
+ // CheckInitializer() - it requires knowledge of the object being initialized.
+
// Immediately handle non-overload placeholders. Overloads can be
// resolved contextually, but everything else here can't.
for (unsigned I = 0, E = InitArgList.size(); I != E; ++I) {
@@ -6117,9 +6231,6 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
}
}
- // Semantic analysis for initializers is done by ActOnDeclarator() and
- // CheckInitializer() - it requires knowledge of the object being initialized.
-
InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitArgList,
RBraceLoc);
E->setType(Context.VoidTy); // FIXME: just a place holder for now.
@@ -6422,8 +6533,28 @@ bool Sema::areLaxCompatibleVectorTypes(QualType srcTy, QualType destTy) {
bool Sema::isLaxVectorConversion(QualType srcTy, QualType destTy) {
assert(destTy->isVectorType() || srcTy->isVectorType());
- if (!Context.getLangOpts().LaxVectorConversions)
+ switch (Context.getLangOpts().getLaxVectorConversions()) {
+ case LangOptions::LaxVectorConversionKind::None:
return false;
+
+ case LangOptions::LaxVectorConversionKind::Integer:
+ if (!srcTy->isIntegralOrEnumerationType()) {
+ auto *Vec = srcTy->getAs<VectorType>();
+ if (!Vec || !Vec->getElementType()->isIntegralOrEnumerationType())
+ return false;
+ }
+ if (!destTy->isIntegralOrEnumerationType()) {
+ auto *Vec = destTy->getAs<VectorType>();
+ if (!Vec || !Vec->getElementType()->isIntegralOrEnumerationType())
+ return false;
+ }
+ // OK, integer (vector) -> integer (vector) bitcast.
+ break;
+
+ case LangOptions::LaxVectorConversionKind::All:
+ break;
+ }
+
return areLaxCompatibleVectorTypes(srcTy, destTy);
}
@@ -6616,8 +6747,8 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
assert(Ty->isVectorType() && "Expected vector type");
SmallVector<Expr *, 8> initExprs;
- const VectorType *VTy = Ty->getAs<VectorType>();
- unsigned numElems = Ty->getAs<VectorType>()->getNumElements();
+ const VectorType *VTy = Ty->castAs<VectorType>();
+ unsigned numElems = VTy->getNumElements();
// '(...)' form of vector initialization in AltiVec: the number of
// initializers must be one or must match the size of the vector.
@@ -6628,7 +6759,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
// vector. If a single value is specified in the initializer then it will
// be replicated to all the components of the vector
if (numExprs == 1) {
- QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
+ QualType ElemTy = VTy->getElementType();
ExprResult Literal = DefaultLvalueConversion(exprs[0]);
if (Literal.isInvalid())
return ExprError();
@@ -6650,7 +6781,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
if (getLangOpts().OpenCL &&
VTy->getVectorKind() == VectorType::GenericVector &&
numExprs == 1) {
- QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
+ QualType ElemTy = VTy->getElementType();
ExprResult Literal = DefaultLvalueConversion(exprs[0]);
if (Literal.isInvalid())
return ExprError();
@@ -6949,8 +7080,8 @@ checkConditionalObjectPointersCompatibility(Sema &S, ExprResult &LHS,
QualType RHSTy = RHS.get()->getType();
// get the "pointed to" types
- QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
- QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
+ QualType lhptee = LHSTy->castAs<PointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->castAs<PointerType>()->getPointeeType();
// ignore qualifiers on void (C99 6.5.15p3, clause 6)
if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) {
@@ -7400,9 +7531,10 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
compositeType = RHSOPT->isObjCBuiltinType() ? RHSTy : LHSTy;
} else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) {
compositeType = LHSOPT->isObjCBuiltinType() ? LHSTy : RHSTy;
- } else if ((LHSTy->isObjCQualifiedIdType() ||
- RHSTy->isObjCQualifiedIdType()) &&
- Context.ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) {
+ } else if ((LHSOPT->isObjCQualifiedIdType() ||
+ RHSOPT->isObjCQualifiedIdType()) &&
+ Context.ObjCQualifiedIdTypesAreCompatible(LHSOPT, RHSOPT,
+ true)) {
// Need to handle "id<xx>" explicitly.
// GCC allows qualified id and any Objective-C type to devolve to
// id. Currently localizing to here until clear this should be
@@ -7434,8 +7566,8 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
LHS = RHS = true;
return QualType();
}
- QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
- QualType rhptee = RHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType lhptee = LHSTy->castAs<PointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->castAs<ObjCObjectPointerType>()->getPointeeType();
QualType destPointee
= Context.getQualifiedType(lhptee, rhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
@@ -7454,8 +7586,8 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
LHS = RHS = true;
return QualType();
}
- QualType lhptee = LHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
- QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
+ QualType lhptee = LHSTy->castAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->castAs<PointerType>()->getPointeeType();
QualType destPointee
= Context.getQualifiedType(rhptee, lhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
@@ -7488,7 +7620,12 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc,
static bool IsArithmeticOp(BinaryOperatorKind Opc) {
return BinaryOperator::isAdditiveOp(Opc) ||
BinaryOperator::isMultiplicativeOp(Opc) ||
- BinaryOperator::isShiftOp(Opc);
+ BinaryOperator::isShiftOp(Opc) || Opc == BO_And || Opc == BO_Or;
+ // This only checks for bitwise-or and bitwise-and, but not bitwise-xor and
+ // not any of the logical operators. Bitwise-xor is commonly used as a
+ // logical-xor because there is no logical-xor operator. The logical
+ // operators, including uses of xor, have a high false positive rate for
+ // precedence warnings.
}
/// IsArithmeticBinaryExpr - Returns true if E is an arithmetic binary
@@ -7578,7 +7715,11 @@ static void DiagnoseConditionalPrecedence(Sema &Self,
// The condition is an arithmetic binary expression, with a right-
// hand side that looks boolean, so warn.
- Self.Diag(OpLoc, diag::warn_precedence_conditional)
+ unsigned DiagID = BinaryOperator::isBitwiseOp(CondOpcode)
+ ? diag::warn_precedence_bitwise_conditional
+ : diag::warn_precedence_conditional;
+
+ Self.Diag(OpLoc, DiagID)
<< Condition->getSourceRange()
<< BinaryOperator::getOpcodeStr(CondOpcode);
@@ -7960,8 +8101,8 @@ checkObjCPointerTypesForAssignment(Sema &S, QualType LHSType,
return Sema::IncompatiblePointer;
return Sema::Compatible;
}
- QualType lhptee = LHSType->getAs<ObjCObjectPointerType>()->getPointeeType();
- QualType rhptee = RHSType->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType lhptee = LHSType->castAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType rhptee = RHSType->castAs<ObjCObjectPointerType>()->getPointeeType();
if (!lhptee.isAtLeastAsQualifiedAs(rhptee) &&
// make an exception for id<P>
@@ -9063,7 +9204,7 @@ static void checkArithmeticNull(Sema &S, ExprResult &LHS, ExprResult &RHS,
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
}
-static void DiagnoseDivisionSizeofPointer(Sema &S, Expr *LHS, Expr *RHS,
+static void DiagnoseDivisionSizeofPointerOrArray(Sema &S, Expr *LHS, Expr *RHS,
SourceLocation Loc) {
const auto *LUE = dyn_cast<UnaryExprOrTypeTraitExpr>(LHS);
const auto *RUE = dyn_cast<UnaryExprOrTypeTraitExpr>(RHS);
@@ -9073,7 +9214,8 @@ static void DiagnoseDivisionSizeofPointer(Sema &S, Expr *LHS, Expr *RHS,
RUE->getKind() != UETT_SizeOf)
return;
- QualType LHSTy = LUE->getArgumentExpr()->IgnoreParens()->getType();
+ const Expr *LHSArg = LUE->getArgumentExpr()->IgnoreParens();
+ QualType LHSTy = LHSArg->getType();
QualType RHSTy;
if (RUE->isArgumentType())
@@ -9081,12 +9223,33 @@ static void DiagnoseDivisionSizeofPointer(Sema &S, Expr *LHS, Expr *RHS,
else
RHSTy = RUE->getArgumentExpr()->IgnoreParens()->getType();
- if (!LHSTy->isPointerType() || RHSTy->isPointerType())
- return;
- if (LHSTy->getPointeeType() != RHSTy)
- return;
+ if (LHSTy->isPointerType() && !RHSTy->isPointerType()) {
+ if (!S.Context.hasSameUnqualifiedType(LHSTy->getPointeeType(), RHSTy))
+ return;
- S.Diag(Loc, diag::warn_division_sizeof_ptr) << LHS << LHS->getSourceRange();
+ S.Diag(Loc, diag::warn_division_sizeof_ptr) << LHS << LHS->getSourceRange();
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(LHSArg)) {
+ if (const ValueDecl *LHSArgDecl = DRE->getDecl())
+ S.Diag(LHSArgDecl->getLocation(), diag::note_pointer_declared_here)
+ << LHSArgDecl;
+ }
+ } else if (const auto *ArrayTy = S.Context.getAsArrayType(LHSTy)) {
+ QualType ArrayElemTy = ArrayTy->getElementType();
+ if (ArrayElemTy != S.Context.getBaseElementType(ArrayTy) ||
+ ArrayElemTy->isDependentType() || RHSTy->isDependentType() ||
+ ArrayElemTy->isCharType() ||
+ S.Context.getTypeSize(ArrayElemTy) == S.Context.getTypeSize(RHSTy))
+ return;
+ S.Diag(Loc, diag::warn_division_sizeof_array)
+ << LHSArg->getSourceRange() << ArrayElemTy << RHSTy;
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(LHSArg)) {
+ if (const ValueDecl *LHSArgDecl = DRE->getDecl())
+ S.Diag(LHSArgDecl->getLocation(), diag::note_array_declared_here)
+ << LHSArgDecl;
+ }
+
+ S.Diag(Loc, diag::note_precedence_silence) << RHS;
+ }
}
static void DiagnoseBadDivideOrRemainderValues(Sema& S, ExprResult &LHS,
@@ -9122,7 +9285,7 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
return InvalidOperands(Loc, LHS, RHS);
if (IsDiv) {
DiagnoseBadDivideOrRemainderValues(*this, LHS, RHS, Loc, IsDiv);
- DiagnoseDivisionSizeofPointer(*this, LHS.get(), RHS.get(), Loc);
+ DiagnoseDivisionSizeofPointerOrArray(*this, LHS.get(), RHS.get(), Loc);
}
return compType;
}
@@ -9281,8 +9444,8 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc,
// if both are pointers check if operation is valid wrt address spaces
if (S.getLangOpts().OpenCL && isLHSPointer && isRHSPointer) {
- const PointerType *lhsPtr = LHSExpr->getType()->getAs<PointerType>();
- const PointerType *rhsPtr = RHSExpr->getType()->getAs<PointerType>();
+ const PointerType *lhsPtr = LHSExpr->getType()->castAs<PointerType>();
+ const PointerType *rhsPtr = RHSExpr->getType()->castAs<PointerType>();
if (!lhsPtr->isAddressSpaceOverlapping(*rhsPtr)) {
S.Diag(Loc,
diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
@@ -9914,8 +10077,8 @@ static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc,
QualType T = S.FindCompositePointerType(Loc, LHS, RHS);
if (T.isNull()) {
- if ((LHSType->isPointerType() || LHSType->isMemberPointerType()) &&
- (RHSType->isPointerType() || RHSType->isMemberPointerType()))
+ if ((LHSType->isAnyPointerType() || LHSType->isMemberPointerType()) &&
+ (RHSType->isAnyPointerType() || RHSType->isMemberPointerType()))
diagnoseDistinctPointerComparison(S, Loc, LHS, RHS, /*isError*/true);
else
S.InvalidOperands(Loc, LHS, RHS);
@@ -10129,20 +10292,18 @@ static void diagnoseLogicalNotOnLHSofCheck(Sema &S, ExprResult &LHS,
<< FixItHint::CreateInsertion(SecondClose, ")");
}
-// Get the decl for a simple expression: a reference to a variable,
-// an implicit C++ field reference, or an implicit ObjC ivar reference.
-static ValueDecl *getCompareDecl(Expr *E) {
- if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
- return DR->getDecl();
- if (ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E)) {
- if (Ivar->isFreeIvar())
- return Ivar->getDecl();
- }
- if (MemberExpr *Mem = dyn_cast<MemberExpr>(E)) {
+// Returns true if E refers to a non-weak array.
+static bool checkForArray(const Expr *E) {
+ const ValueDecl *D = nullptr;
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) {
+ D = DR->getDecl();
+ } else if (const MemberExpr *Mem = dyn_cast<MemberExpr>(E)) {
if (Mem->isImplicitAccess())
- return Mem->getMemberDecl();
+ D = Mem->getMemberDecl();
}
- return nullptr;
+ if (!D)
+ return false;
+ return D->getType()->isArrayType() && !D->isWeak();
}
/// Diagnose some forms of syntactically-obvious tautological comparison.
@@ -10175,47 +10336,54 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
// obvious cases in the definition of the template anyways. The idea is to
// warn when the typed comparison operator will always evaluate to the same
// result.
- ValueDecl *DL = getCompareDecl(LHSStripped);
- ValueDecl *DR = getCompareDecl(RHSStripped);
- if (DL && DR && declaresSameEntity(DL, DR)) {
- StringRef Result;
+
+ // Used for indexing into %select in warn_comparison_always
+ enum {
+ AlwaysConstant,
+ AlwaysTrue,
+ AlwaysFalse,
+ AlwaysEqual, // std::strong_ordering::equal from operator<=>
+ };
+
+ if (Expr::isSameComparisonOperand(LHS, RHS)) {
+ unsigned Result;
switch (Opc) {
case BO_EQ: case BO_LE: case BO_GE:
- Result = "true";
+ Result = AlwaysTrue;
break;
case BO_NE: case BO_LT: case BO_GT:
- Result = "false";
+ Result = AlwaysFalse;
break;
case BO_Cmp:
- Result = "'std::strong_ordering::equal'";
+ Result = AlwaysEqual;
break;
default:
+ Result = AlwaysConstant;
break;
}
S.DiagRuntimeBehavior(Loc, nullptr,
S.PDiag(diag::warn_comparison_always)
- << 0 /*self-comparison*/ << !Result.empty()
+ << 0 /*self-comparison*/
<< Result);
- } else if (DL && DR &&
- DL->getType()->isArrayType() && DR->getType()->isArrayType() &&
- !DL->isWeak() && !DR->isWeak()) {
+ } else if (checkForArray(LHSStripped) && checkForArray(RHSStripped)) {
// What is it always going to evaluate to?
- StringRef Result;
+ unsigned Result;
switch(Opc) {
case BO_EQ: // e.g. array1 == array2
- Result = "false";
+ Result = AlwaysFalse;
break;
case BO_NE: // e.g. array1 != array2
- Result = "true";
+ Result = AlwaysTrue;
break;
default: // e.g. array1 <= array2
// The best we can say is 'a constant'
+ Result = AlwaysConstant;
break;
}
S.DiagRuntimeBehavior(Loc, nullptr,
S.PDiag(diag::warn_comparison_always)
<< 1 /*array comparison*/
- << !Result.empty() << Result);
+ << Result);
}
if (isa<CastExpr>(LHSStripped))
@@ -10370,7 +10538,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
return QualType();
}
QualType IntType =
- LHSStrippedType->getAs<EnumType>()->getDecl()->getIntegerType();
+ LHSStrippedType->castAs<EnumType>()->getDecl()->getIntegerType();
assert(IntType->isArithmeticType());
// We can't use `CK_IntegralCast` when the underlying type is 'bool', so we
@@ -10446,6 +10614,32 @@ static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS,
return S.Context.getLogicalOperationType();
}
+void Sema::CheckPtrComparisonWithNullChar(ExprResult &E, ExprResult &NullE) {
+ if (!NullE.get()->getType()->isAnyPointerType())
+ return;
+ int NullValue = PP.isMacroDefined("NULL") ? 0 : 1;
+ if (!E.get()->getType()->isAnyPointerType() &&
+ E.get()->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNotNull) ==
+ Expr::NPCK_ZeroExpression) {
+ if (const auto *CL = dyn_cast<CharacterLiteral>(E.get())) {
+ if (CL->getValue() == 0)
+ Diag(E.get()->getExprLoc(), diag::warn_pointer_compare)
+ << NullValue
+ << FixItHint::CreateReplacement(E.get()->getExprLoc(),
+ NullValue ? "NULL" : "(void *)0");
+ } else if (const auto *CE = dyn_cast<CStyleCastExpr>(E.get())) {
+ TypeSourceInfo *TI = CE->getTypeInfoAsWritten();
+ QualType T = Context.getCanonicalType(TI->getType()).getUnqualifiedType();
+ if (T == Context.CharTy)
+ Diag(E.get()->getExprLoc(), diag::warn_pointer_compare)
+ << NullValue
+ << FixItHint::CreateReplacement(E.get()->getExprLoc(),
+ NullValue ? "NULL" : "(void *)0");
+ }
+ }
+}
+
// C99 6.5.8, C++ [expr.rel]
QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
@@ -10479,6 +10673,10 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
}
checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/true);
+ if (!getLangOpts().CPlusPlus && BinaryOperator::isEqualityOp(Opc)) {
+ CheckPtrComparisonWithNullChar(LHS, RHS);
+ CheckPtrComparisonWithNullChar(RHS, LHS);
+ }
// Handle vector comparisons separately.
if (LHS.get()->getType()->isVectorType() ||
@@ -10623,8 +10821,8 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
if (LCanPointeeTy != RCanPointeeTy) {
// Treat NULL constant as a special case in OpenCL.
if (getLangOpts().OpenCL && !LHSIsNull && !RHSIsNull) {
- const PointerType *LHSPtr = LHSType->getAs<PointerType>();
- if (!LHSPtr->isAddressSpaceOverlapping(*RHSType->getAs<PointerType>())) {
+ const PointerType *LHSPtr = LHSType->castAs<PointerType>();
+ if (!LHSPtr->isAddressSpaceOverlapping(*RHSType->castAs<PointerType>())) {
Diag(Loc,
diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
<< LHSType << RHSType << 0 /* comparison */
@@ -10889,7 +11087,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// the largest type to the smallest type to avoid cases where long long == long,
// where long gets picked over long long.
QualType Sema::GetSignedVectorType(QualType V) {
- const VectorType *VTy = V->getAs<VectorType>();
+ const VectorType *VTy = V->castAs<VectorType>();
unsigned TypeSize = Context.getTypeSize(VTy->getElementType());
if (isa<ExtVectorType>(VTy)) {
@@ -10944,7 +11142,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
// If AltiVec, the comparison results in a numeric type, i.e.
// bool for C++, int for C
if (getLangOpts().AltiVec &&
- vType->getAs<VectorType>()->getVectorKind() == VectorType::AltiVecVector)
+ vType->castAs<VectorType>()->getVectorKind() == VectorType::AltiVecVector)
return Context.getLogicalOperationType();
// For non-floating point types, check for self-comparisons of the form
@@ -10963,6 +11161,120 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
return GetSignedVectorType(vType);
}
+static void diagnoseXorMisusedAsPow(Sema &S, const ExprResult &XorLHS,
+ const ExprResult &XorRHS,
+ const SourceLocation Loc) {
+ // Do not diagnose macros.
+ if (Loc.isMacroID())
+ return;
+
+ bool Negative = false;
+ bool ExplicitPlus = false;
+ const auto *LHSInt = dyn_cast<IntegerLiteral>(XorLHS.get());
+ const auto *RHSInt = dyn_cast<IntegerLiteral>(XorRHS.get());
+
+ if (!LHSInt)
+ return;
+ if (!RHSInt) {
+ // Check negative literals.
+ if (const auto *UO = dyn_cast<UnaryOperator>(XorRHS.get())) {
+ UnaryOperatorKind Opc = UO->getOpcode();
+ if (Opc != UO_Minus && Opc != UO_Plus)
+ return;
+ RHSInt = dyn_cast<IntegerLiteral>(UO->getSubExpr());
+ if (!RHSInt)
+ return;
+ Negative = (Opc == UO_Minus);
+ ExplicitPlus = !Negative;
+ } else {
+ return;
+ }
+ }
+
+ const llvm::APInt &LeftSideValue = LHSInt->getValue();
+ llvm::APInt RightSideValue = RHSInt->getValue();
+ if (LeftSideValue != 2 && LeftSideValue != 10)
+ return;
+
+ if (LeftSideValue.getBitWidth() != RightSideValue.getBitWidth())
+ return;
+
+ CharSourceRange ExprRange = CharSourceRange::getCharRange(
+ LHSInt->getBeginLoc(), S.getLocForEndOfToken(RHSInt->getLocation()));
+ llvm::StringRef ExprStr =
+ Lexer::getSourceText(ExprRange, S.getSourceManager(), S.getLangOpts());
+
+ CharSourceRange XorRange =
+ CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc));
+ llvm::StringRef XorStr =
+ Lexer::getSourceText(XorRange, S.getSourceManager(), S.getLangOpts());
+ // Do not diagnose if xor keyword/macro is used.
+ if (XorStr == "xor")
+ return;
+
+ std::string LHSStr = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(LHSInt->getSourceRange()),
+ S.getSourceManager(), S.getLangOpts());
+ std::string RHSStr = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(RHSInt->getSourceRange()),
+ S.getSourceManager(), S.getLangOpts());
+
+ if (Negative) {
+ RightSideValue = -RightSideValue;
+ RHSStr = "-" + RHSStr;
+ } else if (ExplicitPlus) {
+ RHSStr = "+" + RHSStr;
+ }
+
+ StringRef LHSStrRef = LHSStr;
+ StringRef RHSStrRef = RHSStr;
+ // Do not diagnose literals with digit separators, binary, hexadecimal, octal
+ // literals.
+ if (LHSStrRef.startswith("0b") || LHSStrRef.startswith("0B") ||
+ RHSStrRef.startswith("0b") || RHSStrRef.startswith("0B") ||
+ LHSStrRef.startswith("0x") || LHSStrRef.startswith("0X") ||
+ RHSStrRef.startswith("0x") || RHSStrRef.startswith("0X") ||
+ (LHSStrRef.size() > 1 && LHSStrRef.startswith("0")) ||
+ (RHSStrRef.size() > 1 && RHSStrRef.startswith("0")) ||
+ LHSStrRef.find('\'') != StringRef::npos ||
+ RHSStrRef.find('\'') != StringRef::npos)
+ return;
+
+ bool SuggestXor = S.getLangOpts().CPlusPlus || S.getPreprocessor().isMacroDefined("xor");
+ const llvm::APInt XorValue = LeftSideValue ^ RightSideValue;
+ int64_t RightSideIntValue = RightSideValue.getSExtValue();
+ if (LeftSideValue == 2 && RightSideIntValue >= 0) {
+ std::string SuggestedExpr = "1 << " + RHSStr;
+ bool Overflow = false;
+ llvm::APInt One = (LeftSideValue - 1);
+ llvm::APInt PowValue = One.sshl_ov(RightSideValue, Overflow);
+ if (Overflow) {
+ if (RightSideIntValue < 64)
+ S.Diag(Loc, diag::warn_xor_used_as_pow_base)
+ << ExprStr << XorValue.toString(10, true) << ("1LL << " + RHSStr)
+ << FixItHint::CreateReplacement(ExprRange, "1LL << " + RHSStr);
+ else if (RightSideIntValue == 64)
+ S.Diag(Loc, diag::warn_xor_used_as_pow) << ExprStr << XorValue.toString(10, true);
+ else
+ return;
+ } else {
+ S.Diag(Loc, diag::warn_xor_used_as_pow_base_extra)
+ << ExprStr << XorValue.toString(10, true) << SuggestedExpr
+ << PowValue.toString(10, true)
+ << FixItHint::CreateReplacement(
+ ExprRange, (RightSideIntValue == 0) ? "1" : SuggestedExpr);
+ }
+
+ S.Diag(Loc, diag::note_xor_used_as_pow_silence) << ("0x2 ^ " + RHSStr) << SuggestXor;
+ } else if (LeftSideValue == 10) {
+ std::string SuggestedValue = "1e" + std::to_string(RightSideIntValue);
+ S.Diag(Loc, diag::warn_xor_used_as_pow_base)
+ << ExprStr << XorValue.toString(10, true) << SuggestedValue
+ << FixItHint::CreateReplacement(ExprRange, SuggestedValue);
+ S.Diag(Loc, diag::note_xor_used_as_pow_silence) << ("0xA ^ " + RHSStr) << SuggestXor;
+ }
+}
+
QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc) {
// Ensure that either both operands are of the same vector type, or
@@ -11014,6 +11326,9 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS,
LHS = LHSResult.get();
RHS = RHSResult.get();
+ if (Opc == BO_Xor)
+ diagnoseXorMisusedAsPow(*this, LHS, RHS, Loc);
+
if (!compType.isNull() && compType->isIntegralOrUnscopedEnumerationType())
return compType;
return InvalidOperands(Loc, LHS, RHS);
@@ -11027,10 +11342,22 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS,
if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType())
return CheckVectorLogicalOperands(LHS, RHS, Loc);
+ bool EnumConstantInBoolContext = false;
+ for (const ExprResult &HS : {LHS, RHS}) {
+ if (const auto *DREHS = dyn_cast<DeclRefExpr>(HS.get())) {
+ const auto *ECDHS = dyn_cast<EnumConstantDecl>(DREHS->getDecl());
+ if (ECDHS && ECDHS->getInitVal() != 0 && ECDHS->getInitVal() != 1)
+ EnumConstantInBoolContext = true;
+ }
+ }
+
+ if (EnumConstantInBoolContext)
+ Diag(Loc, diag::warn_enum_constant_in_bool_context);
+
// Diagnose cases where the user write a logical and/or but probably meant a
// bitwise one. We do this when the LHS is a non-bool integer and the RHS
// is a constant.
- if (LHS.get()->getType()->isIntegerType() &&
+ if (!EnumConstantInBoolContext && LHS.get()->getType()->isIntegerType() &&
!LHS.get()->getType()->isBooleanType() &&
RHS.get()->getType()->isIntegerType() && !RHS.get()->isValueDependent() &&
// Don't warn in macros or template instantiations.
@@ -11651,6 +11978,21 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
CheckForNullPointerDereference(*this, LHSExpr);
+ if (getLangOpts().CPlusPlus2a && LHSType.isVolatileQualified()) {
+ if (CompoundType.isNull()) {
+ // C++2a [expr.ass]p5:
+ // A simple-assignment whose left operand is of a volatile-qualified
+ // type is deprecated unless the assignment is either a discarded-value
+ // expression or an unevaluated operand
+ ExprEvalContexts.back().VolatileAssignmentLHSs.push_back(LHSExpr);
+ } else {
+ // C++2a [expr.ass]p6:
+ // [Compound-assignment] expressions are deprecated if E1 has
+ // volatile-qualified type
+ Diag(Loc, diag::warn_deprecated_compound_assign_volatile) << LHSType;
+ }
+ }
+
// C99 6.5.16p3: The type of an assignment expression is the type of the
// left operand unless the left operand has qualified type, in which case
// it is the unqualified version of the type of the left operand.
@@ -11824,11 +12166,11 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
} else if (S.getLangOpts().AltiVec && ResType->isVectorType()) {
// OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 )
} else if (S.getLangOpts().ZVector && ResType->isVectorType() &&
- (ResType->getAs<VectorType>()->getVectorKind() !=
+ (ResType->castAs<VectorType>()->getVectorKind() !=
VectorType::AltiVecBool)) {
// The z vector extensions allow ++ and -- for non-bool vectors.
} else if(S.getLangOpts().OpenCL && ResType->isVectorType() &&
- ResType->getAs<VectorType>()->getElementType()->isIntegerType()) {
+ ResType->castAs<VectorType>()->getElementType()->isIntegerType()) {
// OpenCL V1.2 6.3 says dec/inc ops operate on integer vector types.
} else {
S.Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement)
@@ -11839,6 +12181,12 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
// Now make sure the operand is a modifiable lvalue.
if (CheckForModifiableLvalue(Op, OpLoc, S))
return QualType();
+ if (S.getLangOpts().CPlusPlus2a && ResType.isVolatileQualified()) {
+ // C++2a [expr.pre.inc]p1, [expr.post.inc]p1:
+ // An operand with volatile-qualified type is deprecated
+ S.Diag(OpLoc, diag::warn_deprecated_increment_decrement_volatile)
+ << IsInc << ResType;
+ }
// In C++, a prefix increment is the same type as the operand. Otherwise
// (in C or with postfix), the increment is the unqualified type of the
// operand.
@@ -12414,7 +12762,7 @@ static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS,
LHS = convertVector(LHS.get(), Context.FloatTy, S);
auto *BO = new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, BinOpResTy,
VK, OK, OpLoc, FPFeatures);
- return convertVector(BO, ResultTy->getAs<VectorType>()->getElementType(), S);
+ return convertVector(BO, ResultTy->castAs<VectorType>()->getElementType(), S);
}
static std::pair<ExprResult, ExprResult>
@@ -12971,6 +13319,13 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc,
S.LookupOverloadedOperatorName(OverOp, Sc, LHS->getType(),
RHS->getType(), Functions);
+ // In C++20 onwards, we may have a second operator to look up.
+ if (S.getLangOpts().CPlusPlus2a) {
+ if (OverloadedOperatorKind ExtraOp = getRewrittenOverloadedOperator(OverOp))
+ S.LookupOverloadedOperatorName(ExtraOp, Sc, LHS->getType(),
+ RHS->getType(), Functions);
+ }
+
// Build the (potentially-overloaded, potentially-dependent)
// binary operation.
return S.CreateOverloadedBinOp(OpLoc, Opc, Functions, LHS, RHS);
@@ -13170,7 +13525,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
else if (resultType->isVectorType() &&
// The z vector extensions don't allow + or - with bool vectors.
(!Context.getLangOpts().ZVector ||
- resultType->getAs<VectorType>()->getVectorKind() !=
+ resultType->castAs<VectorType>()->getVectorKind() !=
VectorType::AltiVecBool))
break;
else if (getLangOpts().CPlusPlus && // C++ [expr.unary.op]p6
@@ -13186,7 +13541,6 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
if (Input.isInvalid())
return ExprError();
resultType = Input.get()->getType();
-
if (resultType->isDependentType())
break;
// C99 6.5.3.3p1. We allow complex int and float as a GCC extension.
@@ -13199,7 +13553,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
else if (resultType->isExtVectorType() && Context.getLangOpts().OpenCL) {
// OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
// on vector float types.
- QualType T = resultType->getAs<ExtVectorType>()->getElementType();
+ QualType T = resultType->castAs<ExtVectorType>()->getElementType();
if (!T->isIntegerType())
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
@@ -13244,7 +13598,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
!Context.getLangOpts().OpenCLCPlusPlus) {
// OpenCL v1.1 6.3.h: The logical operator not (!) does not
// operate on vector float types.
- QualType T = resultType->getAs<ExtVectorType>()->getElementType();
+ QualType T = resultType->castAs<ExtVectorType>()->getElementType();
if (!T->isIntegerType())
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
@@ -13728,10 +14082,11 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) {
BlockDecl *Block = BlockDecl::Create(Context, CurContext, CaretLoc);
if (LangOpts.CPlusPlus) {
+ MangleNumberingContext *MCtx;
Decl *ManglingContextDecl;
- if (MangleNumberingContext *MCtx =
- getCurrentMangleNumberContext(Block->getDeclContext(),
- ManglingContextDecl)) {
+ std::tie(MCtx, ManglingContextDecl) =
+ getCurrentMangleNumberContext(Block->getDeclContext());
+ if (MCtx) {
unsigned ManglingNumber = MCtx->getManglingNumber(Block);
Block->setBlockMangling(ManglingNumber, ManglingContextDecl);
}
@@ -13909,7 +14264,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
// If the user wrote a function type in some form, try to use that.
if (!BSI->FunctionType.isNull()) {
- const FunctionType *FTy = BSI->FunctionType->getAs<FunctionType>();
+ const FunctionType *FTy = BSI->FunctionType->castAs<FunctionType>();
FunctionType::ExtInfo Ext = FTy->getExtInfo();
if (NoReturn && !Ext.getNoReturn()) Ext = Ext.withNoReturn(true);
@@ -14381,24 +14736,24 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
case IncompatibleObjCQualifiedId: {
if (SrcType->isObjCQualifiedIdType()) {
const ObjCObjectPointerType *srcOPT =
- SrcType->getAs<ObjCObjectPointerType>();
+ SrcType->castAs<ObjCObjectPointerType>();
for (auto *srcProto : srcOPT->quals()) {
PDecl = srcProto;
break;
}
if (const ObjCInterfaceType *IFaceT =
- DstType->getAs<ObjCObjectPointerType>()->getInterfaceType())
+ DstType->castAs<ObjCObjectPointerType>()->getInterfaceType())
IFace = IFaceT->getDecl();
}
else if (DstType->isObjCQualifiedIdType()) {
const ObjCObjectPointerType *dstOPT =
- DstType->getAs<ObjCObjectPointerType>();
+ DstType->castAs<ObjCObjectPointerType>();
for (auto *dstProto : dstOPT->quals()) {
PDecl = dstProto;
break;
}
if (const ObjCInterfaceType *IFaceT =
- SrcType->getAs<ObjCObjectPointerType>()->getInterfaceType())
+ SrcType->castAs<ObjCObjectPointerType>()->getInterfaceType())
IFace = IFaceT->getDecl();
}
DiagKind = diag::warn_incompatible_qualified_id;
@@ -14775,6 +15130,26 @@ void Sema::WarnOnPendingNoDerefs(ExpressionEvaluationContextRecord &Rec) {
Rec.PossibleDerefs.clear();
}
+/// Check whether E, which is either a discarded-value expression or an
+/// unevaluated operand, is a simple-assignment to a volatlie-qualified lvalue,
+/// and if so, remove it from the list of volatile-qualified assignments that
+/// we are going to warn are deprecated.
+void Sema::CheckUnusedVolatileAssignment(Expr *E) {
+ if (!E->getType().isVolatileQualified() || !getLangOpts().CPlusPlus2a)
+ return;
+
+ // Note: ignoring parens here is not justified by the standard rules, but
+ // ignoring parentheses seems like a more reasonable approach, and this only
+ // drives a deprecation warning so doesn't affect conformance.
+ if (auto *BO = dyn_cast<BinaryOperator>(E->IgnoreParenImpCasts())) {
+ if (BO->getOpcode() == BO_Assign) {
+ auto &LHSs = ExprEvalContexts.back().VolatileAssignmentLHSs;
+ LHSs.erase(std::remove(LHSs.begin(), LHSs.end(), BO->getLHS()),
+ LHSs.end());
+ }
+ }
+}
+
void Sema::PopExpressionEvaluationContext() {
ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back();
unsigned NumTypos = Rec.NumTypos;
@@ -14809,6 +15184,13 @@ void Sema::PopExpressionEvaluationContext() {
WarnOnPendingNoDerefs(Rec);
+ // Warn on any volatile-qualified simple-assignments that are not discarded-
+ // value expressions nor unevaluated operands (those cases get removed from
+ // this list by CheckUnusedVolatileAssignment).
+ for (auto *BO : Rec.VolatileAssignmentLHSs)
+ Diag(BO->getBeginLoc(), diag::warn_deprecated_simple_assign_volatile)
+ << BO->getType();
+
// When are coming out of an unevaluated context, clear out any
// temporaries that we may have created as part of the evaluation of
// the expression in that context: they aren't relevant because they
@@ -15032,6 +15414,17 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
if (IsRecursiveCall && OdrUse == OdrUseContext::Used)
OdrUse = OdrUseContext::FormallyOdrUsed;
+ // Trivial default constructors and destructors are never actually used.
+ // FIXME: What about other special members?
+ if (Func->isTrivial() && !Func->hasAttr<DLLExportAttr>() &&
+ OdrUse == OdrUseContext::Used) {
+ if (auto *Constructor = dyn_cast<CXXConstructorDecl>(Func))
+ if (Constructor->isDefaultConstructor())
+ OdrUse = OdrUseContext::FormallyOdrUsed;
+ if (isa<CXXDestructorDecl>(Func))
+ OdrUse = OdrUseContext::FormallyOdrUsed;
+ }
+
// C++20 [expr.const]p12:
// A function [...] is needed for constant evaluation if it is [...] a
// constexpr function that is named by an expression that is potentially
@@ -15092,98 +15485,101 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
// If we need a definition, try to create one.
if (NeedDefinition && !Func->getBody()) {
- if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) {
- Constructor = cast<CXXConstructorDecl>(Constructor->getFirstDecl());
- if (Constructor->isDefaulted() && !Constructor->isDeleted()) {
- if (Constructor->isDefaultConstructor()) {
- if (Constructor->isTrivial() &&
- !Constructor->hasAttr<DLLExportAttr>())
+ runWithSufficientStackSpace(Loc, [&] {
+ if (CXXConstructorDecl *Constructor =
+ dyn_cast<CXXConstructorDecl>(Func)) {
+ Constructor = cast<CXXConstructorDecl>(Constructor->getFirstDecl());
+ if (Constructor->isDefaulted() && !Constructor->isDeleted()) {
+ if (Constructor->isDefaultConstructor()) {
+ if (Constructor->isTrivial() &&
+ !Constructor->hasAttr<DLLExportAttr>())
+ return;
+ DefineImplicitDefaultConstructor(Loc, Constructor);
+ } else if (Constructor->isCopyConstructor()) {
+ DefineImplicitCopyConstructor(Loc, Constructor);
+ } else if (Constructor->isMoveConstructor()) {
+ DefineImplicitMoveConstructor(Loc, Constructor);
+ }
+ } else if (Constructor->getInheritedConstructor()) {
+ DefineInheritingConstructor(Loc, Constructor);
+ }
+ } else if (CXXDestructorDecl *Destructor =
+ dyn_cast<CXXDestructorDecl>(Func)) {
+ Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl());
+ if (Destructor->isDefaulted() && !Destructor->isDeleted()) {
+ if (Destructor->isTrivial() && !Destructor->hasAttr<DLLExportAttr>())
return;
- DefineImplicitDefaultConstructor(Loc, Constructor);
- } else if (Constructor->isCopyConstructor()) {
- DefineImplicitCopyConstructor(Loc, Constructor);
- } else if (Constructor->isMoveConstructor()) {
- DefineImplicitMoveConstructor(Loc, Constructor);
+ DefineImplicitDestructor(Loc, Destructor);
}
- } else if (Constructor->getInheritedConstructor()) {
- DefineInheritingConstructor(Loc, Constructor);
- }
- } else if (CXXDestructorDecl *Destructor =
- dyn_cast<CXXDestructorDecl>(Func)) {
- Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl());
- if (Destructor->isDefaulted() && !Destructor->isDeleted()) {
- if (Destructor->isTrivial() && !Destructor->hasAttr<DLLExportAttr>())
- return;
- DefineImplicitDestructor(Loc, Destructor);
+ if (Destructor->isVirtual() && getLangOpts().AppleKext)
+ MarkVTableUsed(Loc, Destructor->getParent());
+ } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) {
+ if (MethodDecl->isOverloadedOperator() &&
+ MethodDecl->getOverloadedOperator() == OO_Equal) {
+ MethodDecl = cast<CXXMethodDecl>(MethodDecl->getFirstDecl());
+ if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) {
+ if (MethodDecl->isCopyAssignmentOperator())
+ DefineImplicitCopyAssignment(Loc, MethodDecl);
+ else if (MethodDecl->isMoveAssignmentOperator())
+ DefineImplicitMoveAssignment(Loc, MethodDecl);
+ }
+ } else if (isa<CXXConversionDecl>(MethodDecl) &&
+ MethodDecl->getParent()->isLambda()) {
+ CXXConversionDecl *Conversion =
+ cast<CXXConversionDecl>(MethodDecl->getFirstDecl());
+ if (Conversion->isLambdaToBlockPointerConversion())
+ DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion);
+ else
+ DefineImplicitLambdaToFunctionPointerConversion(Loc, Conversion);
+ } else if (MethodDecl->isVirtual() && getLangOpts().AppleKext)
+ MarkVTableUsed(Loc, MethodDecl->getParent());
}
- if (Destructor->isVirtual() && getLangOpts().AppleKext)
- MarkVTableUsed(Loc, Destructor->getParent());
- } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) {
- if (MethodDecl->isOverloadedOperator() &&
- MethodDecl->getOverloadedOperator() == OO_Equal) {
- MethodDecl = cast<CXXMethodDecl>(MethodDecl->getFirstDecl());
- if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) {
- if (MethodDecl->isCopyAssignmentOperator())
- DefineImplicitCopyAssignment(Loc, MethodDecl);
- else if (MethodDecl->isMoveAssignmentOperator())
- DefineImplicitMoveAssignment(Loc, MethodDecl);
- }
- } else if (isa<CXXConversionDecl>(MethodDecl) &&
- MethodDecl->getParent()->isLambda()) {
- CXXConversionDecl *Conversion =
- cast<CXXConversionDecl>(MethodDecl->getFirstDecl());
- if (Conversion->isLambdaToBlockPointerConversion())
- DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion);
- else
- DefineImplicitLambdaToFunctionPointerConversion(Loc, Conversion);
- } else if (MethodDecl->isVirtual() && getLangOpts().AppleKext)
- MarkVTableUsed(Loc, MethodDecl->getParent());
- }
- // Implicit instantiation of function templates and member functions of
- // class templates.
- if (Func->isImplicitlyInstantiable()) {
- TemplateSpecializationKind TSK =
- Func->getTemplateSpecializationKindForInstantiation();
- SourceLocation PointOfInstantiation = Func->getPointOfInstantiation();
- bool FirstInstantiation = PointOfInstantiation.isInvalid();
- if (FirstInstantiation) {
- PointOfInstantiation = Loc;
- Func->setTemplateSpecializationKind(TSK, PointOfInstantiation);
- } else if (TSK != TSK_ImplicitInstantiation) {
- // Use the point of use as the point of instantiation, instead of the
- // point of explicit instantiation (which we track as the actual point
- // of instantiation). This gives better backtraces in diagnostics.
- PointOfInstantiation = Loc;
- }
+ // Implicit instantiation of function templates and member functions of
+ // class templates.
+ if (Func->isImplicitlyInstantiable()) {
+ TemplateSpecializationKind TSK =
+ Func->getTemplateSpecializationKindForInstantiation();
+ SourceLocation PointOfInstantiation = Func->getPointOfInstantiation();
+ bool FirstInstantiation = PointOfInstantiation.isInvalid();
+ if (FirstInstantiation) {
+ PointOfInstantiation = Loc;
+ Func->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+ } else if (TSK != TSK_ImplicitInstantiation) {
+ // Use the point of use as the point of instantiation, instead of the
+ // point of explicit instantiation (which we track as the actual point
+ // of instantiation). This gives better backtraces in diagnostics.
+ PointOfInstantiation = Loc;
+ }
- if (FirstInstantiation || TSK != TSK_ImplicitInstantiation ||
- Func->isConstexpr()) {
- if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
- cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
- CodeSynthesisContexts.size())
- PendingLocalImplicitInstantiations.push_back(
- std::make_pair(Func, PointOfInstantiation));
- else if (Func->isConstexpr())
- // Do not defer instantiations of constexpr functions, to avoid the
- // expression evaluator needing to call back into Sema if it sees a
- // call to such a function.
- InstantiateFunctionDefinition(PointOfInstantiation, Func);
- else {
- Func->setInstantiationIsPending(true);
- PendingInstantiations.push_back(
- std::make_pair(Func, PointOfInstantiation));
- // Notify the consumer that a function was implicitly instantiated.
- Consumer.HandleCXXImplicitFunctionInstantiation(Func);
+ if (FirstInstantiation || TSK != TSK_ImplicitInstantiation ||
+ Func->isConstexpr()) {
+ if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
+ cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
+ CodeSynthesisContexts.size())
+ PendingLocalImplicitInstantiations.push_back(
+ std::make_pair(Func, PointOfInstantiation));
+ else if (Func->isConstexpr())
+ // Do not defer instantiations of constexpr functions, to avoid the
+ // expression evaluator needing to call back into Sema if it sees a
+ // call to such a function.
+ InstantiateFunctionDefinition(PointOfInstantiation, Func);
+ else {
+ Func->setInstantiationIsPending(true);
+ PendingInstantiations.push_back(
+ std::make_pair(Func, PointOfInstantiation));
+ // Notify the consumer that a function was implicitly instantiated.
+ Consumer.HandleCXXImplicitFunctionInstantiation(Func);
+ }
+ }
+ } else {
+ // Walk redefinitions, as some of them may be instantiable.
+ for (auto i : Func->redecls()) {
+ if (!i->isUsed(false) && i->isImplicitlyInstantiable())
+ MarkFunctionReferenced(Loc, i, MightBeOdrUse);
}
}
- } else {
- // Walk redefinitions, as some of them may be instantiable.
- for (auto i : Func->redecls()) {
- if (!i->isUsed(false) && i->isImplicitlyInstantiable())
- MarkFunctionReferenced(Loc, i, MightBeOdrUse);
- }
- }
+ });
}
// If this is the first "real" use, act on that.
@@ -15207,9 +15603,14 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
CheckCompleteParameterTypesForMangler(*this, Func, Loc);
Func->markUsed(Context);
+ }
- if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)
+ if (LangOpts.OpenMP) {
+ markOpenMPDeclareVariantFuncsReferenced(Loc, Func, MightBeOdrUse);
+ if (LangOpts.OpenMPIsDevice)
checkOpenMPDeviceFunction(Loc, Func);
+ else
+ checkOpenMPHostFunction(Loc, Func);
}
}
@@ -15447,27 +15848,11 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
// Warn about implicitly autoreleasing indirect parameters captured by blocks.
if (const auto *PT = CaptureType->getAs<PointerType>()) {
- // This function finds out whether there is an AttributedType of kind
- // attr::ObjCOwnership in Ty. The existence of AttributedType of kind
- // attr::ObjCOwnership implies __autoreleasing was explicitly specified
- // rather than being added implicitly by the compiler.
- auto IsObjCOwnershipAttributedType = [](QualType Ty) {
- while (const auto *AttrTy = Ty->getAs<AttributedType>()) {
- if (AttrTy->getAttrKind() == attr::ObjCOwnership)
- return true;
-
- // Peel off AttributedTypes that are not of kind ObjCOwnership.
- Ty = AttrTy->getModifiedType();
- }
-
- return false;
- };
-
QualType PointeeTy = PT->getPointeeType();
if (!Invalid && PointeeTy->getAs<ObjCObjectPointerType>() &&
PointeeTy.getObjCLifetime() == Qualifiers::OCL_Autoreleasing &&
- !IsObjCOwnershipAttributedType(PointeeTy)) {
+ !S.Context.hasDirectOwnershipQualifier(PointeeTy)) {
if (BuildAndDiagnose) {
SourceLocation VarLoc = Var->getLocation();
S.Diag(Loc, diag::warn_block_capture_autoreleasing);
@@ -15517,7 +15902,8 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
if (HasConst)
DeclRefType.addConst();
}
- ByRef = S.isOpenMPCapturedByRef(Var, RSI->OpenMPLevel);
+ ByRef = S.isOpenMPCapturedByRef(Var, RSI->OpenMPLevel,
+ RSI->OpenMPCaptureLevel);
}
if (ByRef)
@@ -15745,7 +16131,25 @@ bool Sema::tryCaptureVariable(
// target region should not be captured outside the scope of the region.
if (RSI->CapRegionKind == CR_OpenMP) {
bool IsOpenMPPrivateDecl = isOpenMPPrivateDecl(Var, RSI->OpenMPLevel);
- auto IsTargetCap = !IsOpenMPPrivateDecl &&
+ // If the variable is private (i.e. not captured) and has variably
+ // modified type, we still need to capture the type for correct
+ // codegen in all regions, associated with the construct. Currently,
+ // it is captured in the innermost captured region only.
+ if (IsOpenMPPrivateDecl && Var->getType()->isVariablyModifiedType()) {
+ QualType QTy = Var->getType();
+ if (ParmVarDecl *PVD = dyn_cast_or_null<ParmVarDecl>(Var))
+ QTy = PVD->getOriginalType();
+ for (int I = 1, E = getNumberOfConstructScopes(RSI->OpenMPLevel);
+ I < E; ++I) {
+ auto *OuterRSI = cast<CapturedRegionScopeInfo>(
+ FunctionScopes[FunctionScopesIndex - I]);
+ assert(RSI->OpenMPLevel == OuterRSI->OpenMPLevel &&
+ "Wrong number of captured regions associated with the "
+ "OpenMP construct.");
+ captureVariablyModifiedType(Context, QTy, OuterRSI);
+ }
+ }
+ bool IsTargetCap = !IsOpenMPPrivateDecl &&
isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel);
// When we detect target captures we are looking from inside the
// target region, therefore we need to propagate the capture from the
@@ -16354,7 +16758,9 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
if (UsableInConstantExpr) {
// Do not defer instantiations of variables that could be used in a
// constant expression.
- SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var);
+ SemaRef.runWithSufficientStackSpace(PointOfInstantiation, [&] {
+ SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var);
+ });
} else if (FirstInstantiation ||
isa<VarTemplateSpecializationDecl>(Var)) {
// FIXME: For a specialization of a variable template, we don't
@@ -17546,6 +17952,9 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
case BuiltinType::Id:
#include "clang/Basic/OpenCLExtensionTypes.def"
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
#define BUILTIN_TYPE(Id, SingletonId) case BuiltinType::Id:
#define PLACEHOLDER_TYPE(Id, SingletonId)
#include "clang/AST/BuiltinTypes.def"
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 705e3b9bd7fb..9aae9289b514 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -453,6 +453,9 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
if (T->isVariablyModifiedType())
return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid) << T);
+ if (CheckQualifiedFunctionForTypeId(T, TypeidLoc))
+ return ExprError();
+
return new (Context) CXXTypeidExpr(TypeInfoType.withConst(), Operand,
SourceRange(TypeidLoc, RParenLoc));
}
@@ -496,6 +499,11 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
}
}
+ ExprResult Result = CheckUnevaluatedOperand(E);
+ if (Result.isInvalid())
+ return ExprError();
+ E = Result.get();
+
// C++ [expr.typeid]p4:
// [...] If the type of the type-id is a reference to a possibly
// cv-qualified type, the result of the typeid expression refers to a
@@ -2108,9 +2116,10 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
QualType InitType;
if (KnownArraySize)
InitType = Context.getConstantArrayType(
- AllocType, llvm::APInt(Context.getTypeSize(Context.getSizeType()),
- *KnownArraySize),
- ArrayType::Normal, 0);
+ AllocType,
+ llvm::APInt(Context.getTypeSize(Context.getSizeType()),
+ *KnownArraySize),
+ *ArraySize, ArrayType::Normal, 0);
else if (ArraySize)
InitType =
Context.getIncompleteArrayType(AllocType, ArrayType::Normal, 0);
@@ -2457,8 +2466,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// deallocation function's name is looked up in the global scope.
LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName);
if (AllocElemType->isRecordType() && DeleteScope != AFS_Global) {
- CXXRecordDecl *RD
- = cast<CXXRecordDecl>(AllocElemType->getAs<RecordType>()->getDecl());
+ auto *RD =
+ cast<CXXRecordDecl>(AllocElemType->castAs<RecordType>()->getDecl());
LookupQualifiedName(FoundDelete, RD);
}
if (FoundDelete.isAmbiguous())
@@ -3293,7 +3302,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// itself in this case.
return ExprError();
- QualType Pointee = Type->getAs<PointerType>()->getPointeeType();
+ QualType Pointee = Type->castAs<PointerType>()->getPointeeType();
QualType PointeeElem = Context.getBaseElementType(Pointee);
if (Pointee.getAddressSpace() != LangAS::Default &&
@@ -4025,8 +4034,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
case ICK_Complex_Promotion:
case ICK_Complex_Conversion: {
- QualType FromEl = From->getType()->getAs<ComplexType>()->getElementType();
- QualType ToEl = ToType->getAs<ComplexType>()->getElementType();
+ QualType FromEl = From->getType()->castAs<ComplexType>()->getElementType();
+ QualType ToEl = ToType->castAs<ComplexType>()->getElementType();
CastKind CK;
if (FromEl->isRealFloatingType()) {
if (ToEl->isRealFloatingType())
@@ -4605,7 +4614,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
return RD->hasAttr<FinalAttr>();
return false;
case UTT_IsSigned:
- return T->isSignedIntegerType();
+ // Enum types should always return false.
+ // Floating points should always return true.
+ return !T->isEnumeralType() && (T->isFloatingType() || T->isSignedIntegerType());
case UTT_IsUnsigned:
return T->isUnsignedIntegerType();
@@ -5232,7 +5243,13 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
ExprResult Result = Self.BuildBinOp(/*S=*/nullptr, KeyLoc, BO_Assign, &Lhs,
&Rhs);
- if (Result.isInvalid() || SFINAE.hasErrorOccurred())
+ if (Result.isInvalid())
+ return false;
+
+ // Treat the assignment as unused for the purpose of -Wdeprecated-volatile.
+ Self.CheckUnusedVolatileAssignment(Result.get());
+
+ if (SFINAE.hasErrorOccurred())
return false;
if (BTT == BTT_IsAssignable)
@@ -5835,20 +5852,21 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
LVK == RVK && LVK != VK_RValue) {
// DerivedToBase was already handled by the class-specific case above.
// FIXME: Should we allow ObjC conversions here?
- bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion;
- if (CompareReferenceRelationship(
- QuestionLoc, LTy, RTy, DerivedToBase,
- ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible &&
+ bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
+ FunctionConversion;
+ if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, DerivedToBase,
+ ObjCConversion, ObjCLifetimeConversion,
+ FunctionConversion) == Ref_Compatible &&
!DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
// [...] subject to the constraint that the reference must bind
// directly [...]
- !RHS.get()->refersToBitField() &&
- !RHS.get()->refersToVectorElement()) {
+ !RHS.get()->refersToBitField() && !RHS.get()->refersToVectorElement()) {
RHS = ImpCastExprToType(RHS.get(), LTy, CK_NoOp, RVK);
RTy = RHS.get()->getType();
} else if (CompareReferenceRelationship(
- QuestionLoc, RTy, LTy, DerivedToBase,
- ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible &&
+ QuestionLoc, RTy, LTy, DerivedToBase, ObjCConversion,
+ ObjCLifetimeConversion,
+ FunctionConversion) == Ref_Compatible &&
!DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
!LHS.get()->refersToBitField() &&
!LHS.get()->refersToVectorElement()) {
@@ -6603,6 +6621,11 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
ExprEvalContexts.back().ExprContext =
ExpressionEvaluationContextRecord::EK_Other;
+ Result = CheckUnevaluatedOperand(E);
+ if (Result.isInvalid())
+ return ExprError();
+ E = Result.get();
+
// In MS mode, don't perform any extra checking of call return types within a
// decltype expression.
if (getLangOpts().MSVCCompat)
@@ -6794,14 +6817,10 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
// it's legal for the type to be incomplete if this is a pseudo-destructor
// call. We'll do more incomplete-type checks later in the lookup process,
// so just skip this check for ObjC types.
- if (BaseType->isObjCObjectOrInterfaceType()) {
+ if (!BaseType->isRecordType()) {
ObjectType = ParsedType::make(BaseType);
MayBePseudoDestructor = true;
return Base;
- } else if (!BaseType->isRecordType()) {
- ObjectType = nullptr;
- MayBePseudoDestructor = true;
- return Base;
}
// The object type must be complete (or dependent), or
@@ -7173,7 +7192,7 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
if (Method->getParent()->isLambda() &&
Method->getConversionType()->isBlockPointerType()) {
- // This is a lambda coversion to block pointer; check if the argument
+ // This is a lambda conversion to block pointer; check if the argument
// was a LambdaExpr.
Expr *SubE = E;
CastExpr *CE = dyn_cast<CastExpr>(SubE);
@@ -7231,7 +7250,10 @@ ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand,
if (R.isInvalid())
return R;
- // The operand may have been modified when checking the placeholder type.
+ R = CheckUnevaluatedOperand(R.get());
+ if (R.isInvalid())
+ return ExprError();
+
Operand = R.get();
if (!inTemplateInstantiation() && Operand->HasSideEffects(Context, false)) {
@@ -7335,12 +7357,17 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
// volatile lvalue with a special form, we perform an lvalue-to-rvalue
// conversion.
if (getLangOpts().CPlusPlus11 && E->isGLValue() &&
- E->getType().isVolatileQualified() &&
- IsSpecialDiscardedValue(E)) {
- ExprResult Res = DefaultLvalueConversion(E);
- if (Res.isInvalid())
- return E;
- E = Res.get();
+ E->getType().isVolatileQualified()) {
+ if (IsSpecialDiscardedValue(E)) {
+ ExprResult Res = DefaultLvalueConversion(E);
+ if (Res.isInvalid())
+ return E;
+ E = Res.get();
+ } else {
+ // Per C++2a [expr.ass]p5, a volatile assignment is not deprecated if
+ // it occurs as a discarded-value expression.
+ CheckUnusedVolatileAssignment(E);
+ }
}
// C++1z:
@@ -7375,6 +7402,14 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
return E;
}
+ExprResult Sema::CheckUnevaluatedOperand(Expr *E) {
+ // Per C++2a [expr.ass]p5, a volatile assignment is not deprecated if
+ // it occurs as an unevaluated operand.
+ CheckUnusedVolatileAssignment(E);
+
+ return E;
+}
+
// If we can unambiguously determine whether Var can never be used
// in a constant expression, return true.
// - if the variable and its initializer are non-dependent, then
@@ -7584,15 +7619,22 @@ class TransformTypos : public TreeTransform<TransformTypos> {
llvm::SmallDenseMap<OverloadExpr *, Expr *, 4> OverloadResolution;
/// Emit diagnostics for all of the TypoExprs encountered.
+ ///
/// If the TypoExprs were successfully corrected, then the diagnostics should
/// suggest the corrections. Otherwise the diagnostics will not suggest
/// anything (having been passed an empty TypoCorrection).
- void EmitAllDiagnostics() {
+ ///
+ /// If we've failed to correct due to ambiguous corrections, we need to
+ /// be sure to pass empty corrections and replacements. Otherwise it's
+ /// possible that the Consumer has a TypoCorrection that failed to ambiguity
+ /// and we don't want to report those diagnostics.
+ void EmitAllDiagnostics(bool IsAmbiguous) {
for (TypoExpr *TE : TypoExprs) {
auto &State = SemaRef.getTypoExprState(TE);
if (State.DiagHandler) {
- TypoCorrection TC = State.Consumer->getCurrentCorrection();
- ExprResult Replacement = TransformCache[TE];
+ TypoCorrection TC = IsAmbiguous
+ ? TypoCorrection() : State.Consumer->getCurrentCorrection();
+ ExprResult Replacement = IsAmbiguous ? ExprError() : TransformCache[TE];
// Extract the NamedDecl from the transformed TypoExpr and add it to the
// TypoCorrection, replacing the existing decls. This ensures the right
@@ -7654,6 +7696,149 @@ class TransformTypos : public TreeTransform<TransformTypos> {
return ExprFilter(Res.get());
}
+ // Since correcting typos may intoduce new TypoExprs, this function
+ // checks for new TypoExprs and recurses if it finds any. Note that it will
+ // only succeed if it is able to correct all typos in the given expression.
+ ExprResult CheckForRecursiveTypos(ExprResult Res, bool &IsAmbiguous) {
+ if (Res.isInvalid()) {
+ return Res;
+ }
+ // Check to see if any new TypoExprs were created. If so, we need to recurse
+ // to check their validity.
+ Expr *FixedExpr = Res.get();
+
+ auto SavedTypoExprs = std::move(TypoExprs);
+ auto SavedAmbiguousTypoExprs = std::move(AmbiguousTypoExprs);
+ TypoExprs.clear();
+ AmbiguousTypoExprs.clear();
+
+ FindTypoExprs(TypoExprs).TraverseStmt(FixedExpr);
+ if (!TypoExprs.empty()) {
+ // Recurse to handle newly created TypoExprs. If we're not able to
+ // handle them, discard these TypoExprs.
+ ExprResult RecurResult =
+ RecursiveTransformLoop(FixedExpr, IsAmbiguous);
+ if (RecurResult.isInvalid()) {
+ Res = ExprError();
+ // Recursive corrections didn't work, wipe them away and don't add
+ // them to the TypoExprs set. Remove them from Sema's TypoExpr list
+ // since we don't want to clear them twice. Note: it's possible the
+ // TypoExprs were created recursively and thus won't be in our
+ // Sema's TypoExprs - they were created in our `RecursiveTransformLoop`.
+ auto &SemaTypoExprs = SemaRef.TypoExprs;
+ for (auto TE : TypoExprs) {
+ TransformCache.erase(TE);
+ SemaRef.clearDelayedTypo(TE);
+
+ auto SI = find(SemaTypoExprs, TE);
+ if (SI != SemaTypoExprs.end()) {
+ SemaTypoExprs.erase(SI);
+ }
+ }
+ } else {
+ // TypoExpr is valid: add newly created TypoExprs since we were
+ // able to correct them.
+ Res = RecurResult;
+ SavedTypoExprs.set_union(TypoExprs);
+ }
+ }
+
+ TypoExprs = std::move(SavedTypoExprs);
+ AmbiguousTypoExprs = std::move(SavedAmbiguousTypoExprs);
+
+ return Res;
+ }
+
+ // Try to transform the given expression, looping through the correction
+ // candidates with `CheckAndAdvanceTypoExprCorrectionStreams`.
+ //
+ // If valid ambiguous typo corrections are seen, `IsAmbiguous` is set to
+ // true and this method immediately will return an `ExprError`.
+ ExprResult RecursiveTransformLoop(Expr *E, bool &IsAmbiguous) {
+ ExprResult Res;
+ auto SavedTypoExprs = std::move(SemaRef.TypoExprs);
+ SemaRef.TypoExprs.clear();
+
+ while (true) {
+ Res = CheckForRecursiveTypos(TryTransform(E), IsAmbiguous);
+
+ // Recursion encountered an ambiguous correction. This means that our
+ // correction itself is ambiguous, so stop now.
+ if (IsAmbiguous)
+ break;
+
+ // If the transform is still valid after checking for any new typos,
+ // it's good to go.
+ if (!Res.isInvalid())
+ break;
+
+ // The transform was invalid, see if we have any TypoExprs with untried
+ // correction candidates.
+ if (!CheckAndAdvanceTypoExprCorrectionStreams())
+ break;
+ }
+
+ // If we found a valid result, double check to make sure it's not ambiguous.
+ if (!IsAmbiguous && !Res.isInvalid() && !AmbiguousTypoExprs.empty()) {
+ auto SavedTransformCache = std::move(TransformCache);
+ TransformCache.clear();
+ // Ensure none of the TypoExprs have multiple typo correction candidates
+ // with the same edit length that pass all the checks and filters.
+ while (!AmbiguousTypoExprs.empty()) {
+ auto TE = AmbiguousTypoExprs.back();
+
+ // TryTransform itself can create new Typos, adding them to the TypoExpr map
+ // and invalidating our TypoExprState, so always fetch it instead of storing.
+ SemaRef.getTypoExprState(TE).Consumer->saveCurrentPosition();
+
+ TypoCorrection TC = SemaRef.getTypoExprState(TE).Consumer->peekNextCorrection();
+ TypoCorrection Next;
+ do {
+ // Fetch the next correction by erasing the typo from the cache and calling
+ // `TryTransform` which will iterate through corrections in
+ // `TransformTypoExpr`.
+ TransformCache.erase(TE);
+ ExprResult AmbigRes = CheckForRecursiveTypos(TryTransform(E), IsAmbiguous);
+
+ if (!AmbigRes.isInvalid() || IsAmbiguous) {
+ SemaRef.getTypoExprState(TE).Consumer->resetCorrectionStream();
+ SavedTransformCache.erase(TE);
+ Res = ExprError();
+ IsAmbiguous = true;
+ break;
+ }
+ } while ((Next = SemaRef.getTypoExprState(TE).Consumer->peekNextCorrection()) &&
+ Next.getEditDistance(false) == TC.getEditDistance(false));
+
+ if (IsAmbiguous)
+ break;
+
+ AmbiguousTypoExprs.remove(TE);
+ SemaRef.getTypoExprState(TE).Consumer->restoreSavedPosition();
+ }
+ TransformCache = std::move(SavedTransformCache);
+ }
+
+ // Wipe away any newly created TypoExprs that we don't know about. Since we
+ // clear any invalid TypoExprs in `CheckForRecursiveTypos`, this is only
+ // possible if a `TypoExpr` is created during a transformation but then
+ // fails before we can discover it.
+ auto &SemaTypoExprs = SemaRef.TypoExprs;
+ for (auto Iterator = SemaTypoExprs.begin(); Iterator != SemaTypoExprs.end();) {
+ auto TE = *Iterator;
+ auto FI = find(TypoExprs, TE);
+ if (FI != TypoExprs.end()) {
+ Iterator++;
+ continue;
+ }
+ SemaRef.clearDelayedTypo(TE);
+ Iterator = SemaTypoExprs.erase(Iterator);
+ }
+ SemaRef.TypoExprs = std::move(SavedTypoExprs);
+
+ return Res;
+ }
+
public:
TransformTypos(Sema &SemaRef, VarDecl *InitDecl, llvm::function_ref<ExprResult(Expr *)> Filter)
: BaseTransform(SemaRef), InitDecl(InitDecl), ExprFilter(Filter) {}
@@ -7681,49 +7866,13 @@ public:
ExprResult TransformBlockExpr(BlockExpr *E) { return Owned(E); }
ExprResult Transform(Expr *E) {
- ExprResult Res;
- while (true) {
- Res = TryTransform(E);
-
- // Exit if either the transform was valid or if there were no TypoExprs
- // to transform that still have any untried correction candidates..
- if (!Res.isInvalid() ||
- !CheckAndAdvanceTypoExprCorrectionStreams())
- break;
- }
-
- // Ensure none of the TypoExprs have multiple typo correction candidates
- // with the same edit length that pass all the checks and filters.
- // TODO: Properly handle various permutations of possible corrections when
- // there is more than one potentially ambiguous typo correction.
- // Also, disable typo correction while attempting the transform when
- // handling potentially ambiguous typo corrections as any new TypoExprs will
- // have been introduced by the application of one of the correction
- // candidates and add little to no value if corrected.
- SemaRef.DisableTypoCorrection = true;
- while (!AmbiguousTypoExprs.empty()) {
- auto TE = AmbiguousTypoExprs.back();
- auto Cached = TransformCache[TE];
- auto &State = SemaRef.getTypoExprState(TE);
- State.Consumer->saveCurrentPosition();
- TransformCache.erase(TE);
- if (!TryTransform(E).isInvalid()) {
- State.Consumer->resetCorrectionStream();
- TransformCache.erase(TE);
- Res = ExprError();
- break;
- }
- AmbiguousTypoExprs.remove(TE);
- State.Consumer->restoreSavedPosition();
- TransformCache[TE] = Cached;
- }
- SemaRef.DisableTypoCorrection = false;
+ bool IsAmbiguous = false;
+ ExprResult Res = RecursiveTransformLoop(E, IsAmbiguous);
- // Ensure that all of the TypoExprs within the current Expr have been found.
if (!Res.isUsable())
FindTypoExprs(TypoExprs).TraverseStmt(E);
- EmitAllDiagnostics();
+ EmitAllDiagnostics(IsAmbiguous);
return Res;
}
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index c856e37e99e7..87114a0fac63 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -629,7 +629,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<RecordMemberExprValidatorCCC>(*this);
+ return std::make_unique<RecordMemberExprValidatorCCC>(*this);
}
private:
@@ -934,19 +934,19 @@ static bool IsInFnTryBlockHandler(const Scope *S) {
return false;
}
-static VarDecl *
-getVarTemplateSpecialization(Sema &S, VarTemplateDecl *VarTempl,
+VarDecl *
+Sema::getVarTemplateSpecialization(VarTemplateDecl *VarTempl,
const TemplateArgumentListInfo *TemplateArgs,
const DeclarationNameInfo &MemberNameInfo,
SourceLocation TemplateKWLoc) {
if (!TemplateArgs) {
- S.diagnoseMissingTemplateArguments(TemplateName(VarTempl),
- MemberNameInfo.getBeginLoc());
+ diagnoseMissingTemplateArguments(TemplateName(VarTempl),
+ MemberNameInfo.getBeginLoc());
return nullptr;
}
- DeclResult VDecl = S.CheckVarTemplateId(
- VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(), *TemplateArgs);
+ DeclResult VDecl = CheckVarTemplateId(VarTempl, TemplateKWLoc,
+ MemberNameInfo.getLoc(), *TemplateArgs);
if (VDecl.isInvalid())
return nullptr;
VarDecl *Var = cast<VarDecl>(VDecl.get());
@@ -1006,7 +1006,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
// Rederive where we looked up.
DeclContext *DC = (SS.isSet()
? computeDeclContext(SS, false)
- : BaseType->getAs<RecordType>()->getDecl());
+ : BaseType->castAs<RecordType>()->getDecl());
if (ExtraArgs) {
ExprResult RetryExpr;
@@ -1095,7 +1095,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
"How did we get template arguments here sans a variable template");
if (isa<VarTemplateDecl>(MemberDecl)) {
MemberDecl = getVarTemplateSpecialization(
- *this, cast<VarTemplateDecl>(MemberDecl), TemplateArgs,
+ cast<VarTemplateDecl>(MemberDecl), TemplateArgs,
R.getLookupNameInfo(), TemplateKWLoc);
if (!MemberDecl)
return ExprError();
@@ -1160,7 +1160,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
}
if (VarTemplateDecl *VarTempl = dyn_cast<VarTemplateDecl>(MemberDecl)) {
if (VarDecl *Var = getVarTemplateSpecialization(
- *this, VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc))
+ VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc))
return BuildMemberExpr(
BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, FoundDecl,
/*HadMultipleCandidates=*/false, MemberNameInfo,
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 040cfdd30c7a..e18621e42a6b 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -67,7 +67,7 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
const ConstantArrayType *CAT = Context.getAsConstantArrayType(S->getType());
assert(CAT && "String literal not of constant array type!");
QualType StrTy = Context.getConstantArrayType(
- CAT->getElementType(), llvm::APInt(32, StrBuf.size() + 1),
+ CAT->getElementType(), llvm::APInt(32, StrBuf.size() + 1), nullptr,
CAT->getSizeModifier(), CAT->getIndexTypeCVRQualifiers());
S = StringLiteral::Create(Context, StrBuf, StringLiteral::Ascii,
/*Pascal=*/false, StrTy, &StrLocs[0],
@@ -2115,7 +2115,7 @@ class ObjCInterfaceOrSuperCCC final : public CorrectionCandidateCallback {
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<ObjCInterfaceOrSuperCCC>(*this);
+ return std::make_unique<ObjCInterfaceOrSuperCCC>(*this);
}
};
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index bc1069609336..10cb7acad567 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/Designator.h"
#include "clang/Sema/Initialization.h"
@@ -197,7 +198,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
llvm::APInt ConstVal(32, StrLength);
// Return a new array type (C99 6.7.8p22).
DeclT = S.Context.getConstantArrayType(IAT->getElementType(),
- ConstVal,
+ ConstVal, nullptr,
ArrayType::Normal, 0);
updateStringLiteralType(Str, DeclT);
return;
@@ -271,13 +272,24 @@ namespace {
/// point. CheckDesignatedInitializer() recursively steps into the
/// designated subobject and manages backing out the recursion to
/// initialize the subobjects after the one designated.
+///
+/// If an initializer list contains any designators, we build a placeholder
+/// structured list even in 'verify only' mode, so that we can track which
+/// elements need 'empty' initializtion.
class InitListChecker {
Sema &SemaRef;
- bool hadError;
- bool VerifyOnly; // no diagnostics, no structure building
+ bool hadError = false;
+ bool VerifyOnly; // No diagnostics.
bool TreatUnavailableAsInvalid; // Used only in VerifyOnly mode.
- llvm::DenseMap<InitListExpr *, InitListExpr *> SyntacticToSemantic;
- InitListExpr *FullyStructuredList;
+ bool InOverloadResolution;
+ InitListExpr *FullyStructuredList = nullptr;
+ NoInitExpr *DummyExpr = nullptr;
+
+ NoInitExpr *getDummyInit() {
+ if (!DummyExpr)
+ DummyExpr = new (SemaRef.Context) NoInitExpr(SemaRef.Context.VoidTy);
+ return DummyExpr;
+ }
void CheckImplicitInitList(const InitializedEntity &Entity,
InitListExpr *ParentIList, QualType T,
@@ -352,14 +364,71 @@ class InitListChecker {
void UpdateStructuredListElement(InitListExpr *StructuredList,
unsigned &StructuredIndex,
Expr *expr);
+ InitListExpr *createInitListExpr(QualType CurrentObjectType,
+ SourceRange InitRange,
+ unsigned ExpectedNumInits);
int numArrayElements(QualType DeclType);
int numStructUnionElements(QualType DeclType);
- static ExprResult PerformEmptyInit(Sema &SemaRef,
- SourceLocation Loc,
- const InitializedEntity &Entity,
- bool VerifyOnly,
- bool TreatUnavailableAsInvalid);
+ ExprResult PerformEmptyInit(SourceLocation Loc,
+ const InitializedEntity &Entity);
+
+ /// Diagnose that OldInit (or part thereof) has been overridden by NewInit.
+ void diagnoseInitOverride(Expr *OldInit, SourceRange NewInitRange,
+ bool FullyOverwritten = true) {
+ // Overriding an initializer via a designator is valid with C99 designated
+ // initializers, but ill-formed with C++20 designated initializers.
+ unsigned DiagID = SemaRef.getLangOpts().CPlusPlus
+ ? diag::ext_initializer_overrides
+ : diag::warn_initializer_overrides;
+
+ if (InOverloadResolution && SemaRef.getLangOpts().CPlusPlus) {
+ // In overload resolution, we have to strictly enforce the rules, and so
+ // don't allow any overriding of prior initializers. This matters for a
+ // case such as:
+ //
+ // union U { int a, b; };
+ // struct S { int a, b; };
+ // void f(U), f(S);
+ //
+ // Here, f({.a = 1, .b = 2}) is required to call the struct overload. For
+ // consistency, we disallow all overriding of prior initializers in
+ // overload resolution, not only overriding of union members.
+ hadError = true;
+ } else if (OldInit->getType().isDestructedType() && !FullyOverwritten) {
+ // If we'll be keeping around the old initializer but overwriting part of
+ // the object it initialized, and that object is not trivially
+ // destructible, this can leak. Don't allow that, not even as an
+ // extension.
+ //
+ // FIXME: It might be reasonable to allow this in cases where the part of
+ // the initializer that we're overriding has trivial destruction.
+ DiagID = diag::err_initializer_overrides_destructed;
+ } else if (!OldInit->getSourceRange().isValid()) {
+ // We need to check on source range validity because the previous
+ // initializer does not have to be an explicit initializer. e.g.,
+ //
+ // struct P { int a, b; };
+ // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 };
+ //
+ // There is an overwrite taking place because the first braced initializer
+ // list "{ .a = 2 }" already provides value for .p.b (which is zero).
+ //
+ // Such overwrites are harmless, so we don't diagnose them. (Note that in
+ // C++, this cannot be reached unless we've already seen and diagnosed a
+ // different conformance issue, such as a mixture of designated and
+ // non-designated initializers or a multi-level designator.)
+ return;
+ }
+
+ if (!VerifyOnly) {
+ SemaRef.Diag(NewInitRange.getBegin(), DiagID)
+ << NewInitRange << FullyOverwritten << OldInit->getType();
+ SemaRef.Diag(OldInit->getBeginLoc(), diag::note_previous_initializer)
+ << (OldInit->HasSideEffects(SemaRef.Context) && FullyOverwritten)
+ << OldInit->getSourceRange();
+ }
+ }
// Explanation on the "FillWithNoInit" mode:
//
@@ -399,9 +468,9 @@ class InitListChecker {
SourceLocation Loc);
public:
- InitListChecker(Sema &S, const InitializedEntity &Entity,
- InitListExpr *IL, QualType &T, bool VerifyOnly,
- bool TreatUnavailableAsInvalid);
+ InitListChecker(Sema &S, const InitializedEntity &Entity, InitListExpr *IL,
+ QualType &T, bool VerifyOnly, bool TreatUnavailableAsInvalid,
+ bool InOverloadResolution = false);
bool HadError() { return hadError; }
// Retrieves the fully-structured initializer list used for
@@ -411,11 +480,8 @@ public:
} // end anonymous namespace
-ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef,
- SourceLocation Loc,
- const InitializedEntity &Entity,
- bool VerifyOnly,
- bool TreatUnavailableAsInvalid) {
+ExprResult InitListChecker::PerformEmptyInit(SourceLocation Loc,
+ const InitializedEntity &Entity) {
InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc,
true);
MultiExprArg SubInit;
@@ -517,43 +583,44 @@ ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef,
<< Entity.getElementIndex();
}
}
+ hadError = true;
return ExprError();
}
- return VerifyOnly ? ExprResult(static_cast<Expr *>(nullptr))
+ return VerifyOnly ? ExprResult()
: InitSeq.Perform(SemaRef, Entity, Kind, SubInit);
}
void InitListChecker::CheckEmptyInitializable(const InitializedEntity &Entity,
SourceLocation Loc) {
- assert(VerifyOnly &&
- "CheckEmptyInitializable is only inteded for verification mode.");
- if (PerformEmptyInit(SemaRef, Loc, Entity, /*VerifyOnly*/true,
- TreatUnavailableAsInvalid).isInvalid())
- hadError = true;
+ // If we're building a fully-structured list, we'll check this at the end
+ // once we know which elements are actually initialized. Otherwise, we know
+ // that there are no designators so we can just check now.
+ if (FullyStructuredList)
+ return;
+ PerformEmptyInit(Loc, Entity);
}
void InitListChecker::FillInEmptyInitForBase(
unsigned Init, const CXXBaseSpecifier &Base,
const InitializedEntity &ParentEntity, InitListExpr *ILE,
bool &RequiresSecondPass, bool FillWithNoInit) {
- assert(Init < ILE->getNumInits() && "should have been expanded");
-
InitializedEntity BaseEntity = InitializedEntity::InitializeBase(
SemaRef.Context, &Base, false, &ParentEntity);
- if (!ILE->getInit(Init)) {
- ExprResult BaseInit =
- FillWithNoInit
- ? new (SemaRef.Context) NoInitExpr(Base.getType())
- : PerformEmptyInit(SemaRef, ILE->getEndLoc(), BaseEntity,
- /*VerifyOnly*/ false, TreatUnavailableAsInvalid);
+ if (Init >= ILE->getNumInits() || !ILE->getInit(Init)) {
+ ExprResult BaseInit = FillWithNoInit
+ ? new (SemaRef.Context) NoInitExpr(Base.getType())
+ : PerformEmptyInit(ILE->getEndLoc(), BaseEntity);
if (BaseInit.isInvalid()) {
hadError = true;
return;
}
- ILE->setInit(Init, BaseInit.getAs<Expr>());
+ if (!VerifyOnly) {
+ assert(Init < ILE->getNumInits() && "should have been expanded");
+ ILE->setInit(Init, BaseInit.getAs<Expr>());
+ }
} else if (InitListExpr *InnerILE =
dyn_cast<InitListExpr>(ILE->getInit(Init))) {
FillInEmptyInitializations(BaseEntity, InnerILE, RequiresSecondPass,
@@ -576,12 +643,14 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
InitializedEntity MemberEntity
= InitializedEntity::InitializeMember(Field, &ParentEntity);
- if (const RecordType *RType = ILE->getType()->getAs<RecordType>())
- if (!RType->getDecl()->isUnion())
- assert(Init < NumInits && "This ILE should have been expanded");
-
if (Init >= NumInits || !ILE->getInit(Init)) {
+ if (const RecordType *RType = ILE->getType()->getAs<RecordType>())
+ if (!RType->getDecl()->isUnion())
+ assert((Init < NumInits || VerifyOnly) &&
+ "This ILE should have been expanded");
+
if (FillWithNoInit) {
+ assert(!VerifyOnly && "should not fill with no-init in verify-only mode");
Expr *Filler = new (SemaRef.Context) NoInitExpr(Field->getType());
if (Init < NumInits)
ILE->setInit(Init, Filler);
@@ -594,6 +663,9 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
// members in the aggregate, then each member not explicitly initialized
// shall be initialized from its brace-or-equal-initializer [...]
if (Field->hasInClassInitializer()) {
+ if (VerifyOnly)
+ return;
+
ExprResult DIE = SemaRef.BuildCXXDefaultInitExpr(Loc, Field);
if (DIE.isInvalid()) {
hadError = true;
@@ -610,28 +682,28 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
}
if (Field->getType()->isReferenceType()) {
- // C++ [dcl.init.aggr]p9:
- // If an incomplete or empty initializer-list leaves a
- // member of reference type uninitialized, the program is
- // ill-formed.
- SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized)
- << Field->getType()
- << ILE->getSyntacticForm()->getSourceRange();
- SemaRef.Diag(Field->getLocation(),
- diag::note_uninit_reference_member);
+ if (!VerifyOnly) {
+ // C++ [dcl.init.aggr]p9:
+ // If an incomplete or empty initializer-list leaves a
+ // member of reference type uninitialized, the program is
+ // ill-formed.
+ SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized)
+ << Field->getType()
+ << ILE->getSyntacticForm()->getSourceRange();
+ SemaRef.Diag(Field->getLocation(),
+ diag::note_uninit_reference_member);
+ }
hadError = true;
return;
}
- ExprResult MemberInit = PerformEmptyInit(SemaRef, Loc, MemberEntity,
- /*VerifyOnly*/false,
- TreatUnavailableAsInvalid);
+ ExprResult MemberInit = PerformEmptyInit(Loc, MemberEntity);
if (MemberInit.isInvalid()) {
hadError = true;
return;
}
- if (hadError) {
+ if (hadError || VerifyOnly) {
// Do nothing
} else if (Init < NumInits) {
ILE->setInit(Init, MemberInit.getAs<Expr>());
@@ -644,14 +716,15 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
RequiresSecondPass = true;
}
} else if (InitListExpr *InnerILE
- = dyn_cast<InitListExpr>(ILE->getInit(Init)))
+ = dyn_cast<InitListExpr>(ILE->getInit(Init))) {
FillInEmptyInitializations(MemberEntity, InnerILE,
RequiresSecondPass, ILE, Init, FillWithNoInit);
- else if (DesignatedInitUpdateExpr *InnerDIUE
- = dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init)))
+ } else if (DesignatedInitUpdateExpr *InnerDIUE =
+ dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init))) {
FillInEmptyInitializations(MemberEntity, InnerDIUE->getUpdater(),
RequiresSecondPass, ILE, Init,
/*FillWithNoInit =*/true);
+ }
}
/// Recursively replaces NULL values within the given initializer list
@@ -667,6 +740,11 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
assert((ILE->getType() != SemaRef.Context.VoidTy) &&
"Should not have void type");
+ // We don't need to do any checks when just filling NoInitExprs; that can't
+ // fail.
+ if (FillWithNoInit && VerifyOnly)
+ return;
+
// If this is a nested initializer list, we might have changed its contents
// (and therefore some of its properties, such as instantiation-dependence)
// while filling it in. Inform the outer initializer list so that its state
@@ -709,7 +787,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
unsigned NumElems = numStructUnionElements(ILE->getType());
if (RDecl->hasFlexibleArrayMember())
++NumElems;
- if (ILE->getNumInits() < NumElems)
+ if (!VerifyOnly && ILE->getNumInits() < NumElems)
ILE->resizeInits(SemaRef.Context, NumElems);
unsigned Init = 0;
@@ -771,6 +849,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
} else
ElementType = ILE->getType();
+ bool SkipEmptyInitChecks = false;
for (unsigned Init = 0; Init != NumElements; ++Init) {
if (hadError)
return;
@@ -779,21 +858,25 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
ElementEntity.getKind() == InitializedEntity::EK_VectorElement)
ElementEntity.setElementIndex(Init);
- if (Init >= NumInits && ILE->hasArrayFiller())
+ if (Init >= NumInits && (ILE->hasArrayFiller() || SkipEmptyInitChecks))
return;
Expr *InitExpr = (Init < NumInits ? ILE->getInit(Init) : nullptr);
if (!InitExpr && Init < NumInits && ILE->hasArrayFiller())
ILE->setInit(Init, ILE->getArrayFiller());
else if (!InitExpr && !ILE->hasArrayFiller()) {
+ // In VerifyOnly mode, there's no point performing empty initialization
+ // more than once.
+ if (SkipEmptyInitChecks)
+ continue;
+
Expr *Filler = nullptr;
if (FillWithNoInit)
Filler = new (SemaRef.Context) NoInitExpr(ElementType);
else {
ExprResult ElementInit =
- PerformEmptyInit(SemaRef, ILE->getEndLoc(), ElementEntity,
- /*VerifyOnly*/ false, TreatUnavailableAsInvalid);
+ PerformEmptyInit(ILE->getEndLoc(), ElementEntity);
if (ElementInit.isInvalid()) {
hadError = true;
return;
@@ -804,6 +887,8 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
if (hadError) {
// Do nothing
+ } else if (VerifyOnly) {
+ SkipEmptyInitChecks = true;
} else if (Init < NumInits) {
// For arrays, just set the expression used for value-initialization
// of the "holes" in the array.
@@ -829,34 +914,46 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
}
}
} else if (InitListExpr *InnerILE
- = dyn_cast_or_null<InitListExpr>(InitExpr))
+ = dyn_cast_or_null<InitListExpr>(InitExpr)) {
FillInEmptyInitializations(ElementEntity, InnerILE, RequiresSecondPass,
ILE, Init, FillWithNoInit);
- else if (DesignatedInitUpdateExpr *InnerDIUE
- = dyn_cast_or_null<DesignatedInitUpdateExpr>(InitExpr))
+ } else if (DesignatedInitUpdateExpr *InnerDIUE =
+ dyn_cast_or_null<DesignatedInitUpdateExpr>(InitExpr)) {
FillInEmptyInitializations(ElementEntity, InnerDIUE->getUpdater(),
RequiresSecondPass, ILE, Init,
/*FillWithNoInit =*/true);
+ }
}
}
+static bool hasAnyDesignatedInits(const InitListExpr *IL) {
+ for (const Stmt *Init : *IL)
+ if (Init && isa<DesignatedInitExpr>(Init))
+ return true;
+ return false;
+}
+
InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
- InitListExpr *IL, QualType &T,
- bool VerifyOnly,
- bool TreatUnavailableAsInvalid)
- : SemaRef(S), VerifyOnly(VerifyOnly),
- TreatUnavailableAsInvalid(TreatUnavailableAsInvalid) {
- // FIXME: Check that IL isn't already the semantic form of some other
- // InitListExpr. If it is, we'd create a broken AST.
-
- hadError = false;
-
- FullyStructuredList =
- getStructuredSubobjectInit(IL, 0, T, nullptr, 0, IL->getSourceRange());
+ InitListExpr *IL, QualType &T, bool VerifyOnly,
+ bool TreatUnavailableAsInvalid,
+ bool InOverloadResolution)
+ : SemaRef(S), VerifyOnly(VerifyOnly),
+ TreatUnavailableAsInvalid(TreatUnavailableAsInvalid),
+ InOverloadResolution(InOverloadResolution) {
+ if (!VerifyOnly || hasAnyDesignatedInits(IL)) {
+ FullyStructuredList =
+ createInitListExpr(T, IL->getSourceRange(), IL->getNumInits());
+
+ // FIXME: Check that IL isn't already the semantic form of some other
+ // InitListExpr. If it is, we'd create a broken AST.
+ if (!VerifyOnly)
+ FullyStructuredList->setSyntacticForm(IL);
+ }
+
CheckExplicitInitList(Entity, IL, T, FullyStructuredList,
/*TopLevelObject=*/true);
- if (!hadError && !VerifyOnly) {
+ if (!hadError && FullyStructuredList) {
bool RequiresSecondPass = false;
FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass,
/*OuterILE=*/nullptr, /*OuterIndex=*/0);
@@ -877,7 +974,7 @@ int InitListChecker::numArrayElements(QualType DeclType) {
}
int InitListChecker::numStructUnionElements(QualType DeclType) {
- RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl();
+ RecordDecl *structDecl = DeclType->castAs<RecordType>()->getDecl();
int InitializableMembers = 0;
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(structDecl))
InitializableMembers += CXXRD->getNumBases();
@@ -936,7 +1033,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
else if (T->isRecordType())
maxElements = numStructUnionElements(T);
else if (T->isVectorType())
- maxElements = T->getAs<VectorType>()->getNumElements();
+ maxElements = T->castAs<VectorType>()->getNumElements();
else
llvm_unreachable("CheckImplicitInitList(): Illegal type");
@@ -963,7 +1060,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
StructuredSubobjectInitList,
StructuredSubobjectInitIndex);
- if (!VerifyOnly) {
+ if (StructuredSubobjectInitList) {
StructuredSubobjectInitList->setType(T);
unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1);
@@ -977,7 +1074,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
}
// Complain about missing braces.
- if ((T->isArrayType() || T->isRecordType()) &&
+ if (!VerifyOnly && (T->isArrayType() || T->isRecordType()) &&
!ParentIList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) &&
!isIdiomaticBraceElisionEntity(Entity)) {
SemaRef.Diag(StructuredSubobjectInitList->getBeginLoc(),
@@ -993,7 +1090,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
// Warn if this type won't be an aggregate in future versions of C++.
auto *CXXRD = T->getAsCXXRecordDecl();
- if (CXXRD && CXXRD->hasUserDeclaredConstructor()) {
+ if (!VerifyOnly && CXXRD && CXXRD->hasUserDeclaredConstructor()) {
SemaRef.Diag(StructuredSubobjectInitList->getBeginLoc(),
diag::warn_cxx2a_compat_aggregate_init_with_ctors)
<< StructuredSubobjectInitList->getSourceRange() << T;
@@ -1074,67 +1171,46 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
InitListExpr *IList, QualType &T,
InitListExpr *StructuredList,
bool TopLevelObject) {
- if (!VerifyOnly) {
- SyntacticToSemantic[IList] = StructuredList;
- StructuredList->setSyntacticForm(IList);
- }
-
unsigned Index = 0, StructuredIndex = 0;
CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true,
Index, StructuredList, StructuredIndex, TopLevelObject);
- if (!VerifyOnly) {
+ if (StructuredList) {
QualType ExprTy = T;
if (!ExprTy->isArrayType())
ExprTy = ExprTy.getNonLValueExprType(SemaRef.Context);
- IList->setType(ExprTy);
+ if (!VerifyOnly)
+ IList->setType(ExprTy);
StructuredList->setType(ExprTy);
}
if (hadError)
return;
- if (Index < IList->getNumInits()) {
+ // Don't complain for incomplete types, since we'll get an error elsewhere.
+ if (Index < IList->getNumInits() && !T->isIncompleteType()) {
// We have leftover initializers
+ bool ExtraInitsIsError = SemaRef.getLangOpts().CPlusPlus ||
+ (SemaRef.getLangOpts().OpenCL && T->isVectorType());
+ hadError = ExtraInitsIsError;
if (VerifyOnly) {
- if (SemaRef.getLangOpts().CPlusPlus ||
- (SemaRef.getLangOpts().OpenCL &&
- IList->getType()->isVectorType())) {
- hadError = true;
- }
return;
- }
-
- if (StructuredIndex == 1 &&
- IsStringInit(StructuredList->getInit(0), T, SemaRef.Context) ==
- SIF_None) {
- unsigned DK = diag::ext_excess_initializers_in_char_array_initializer;
- if (SemaRef.getLangOpts().CPlusPlus) {
- DK = diag::err_excess_initializers_in_char_array_initializer;
- hadError = true;
- }
- // Special-case
+ } else if (StructuredIndex == 1 &&
+ IsStringInit(StructuredList->getInit(0), T, SemaRef.Context) ==
+ SIF_None) {
+ unsigned DK =
+ ExtraInitsIsError
+ ? diag::err_excess_initializers_in_char_array_initializer
+ : diag::ext_excess_initializers_in_char_array_initializer;
SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK)
<< IList->getInit(Index)->getSourceRange();
- } else if (!T->isIncompleteType()) {
- // Don't complain for incomplete types, since we'll get an error
- // elsewhere
- QualType CurrentObjectType = StructuredList->getType();
- int initKind =
- CurrentObjectType->isArrayType()? 0 :
- CurrentObjectType->isVectorType()? 1 :
- CurrentObjectType->isScalarType()? 2 :
- CurrentObjectType->isUnionType()? 3 :
- 4;
-
- unsigned DK = diag::ext_excess_initializers;
- if (SemaRef.getLangOpts().CPlusPlus) {
- DK = diag::err_excess_initializers;
- hadError = true;
- }
- if (SemaRef.getLangOpts().OpenCL && initKind == 1) {
- DK = diag::err_excess_initializers;
- hadError = true;
- }
-
+ } else {
+ int initKind = T->isArrayType() ? 0 :
+ T->isVectorType() ? 1 :
+ T->isScalarType() ? 2 :
+ T->isUnionType() ? 3 :
+ 4;
+
+ unsigned DK = ExtraInitsIsError ? diag::err_excess_initializers
+ : diag::ext_excess_initializers;
SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK)
<< initKind << IList->getInit(Index)->getSourceRange();
}
@@ -1188,7 +1264,7 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
} else if (DeclType->isRecordType()) {
assert(DeclType->isAggregateType() &&
"non-aggregate records should be handed in CheckSubElementType");
- RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl();
auto Bases =
CXXRecordDecl::base_class_range(CXXRecordDecl::base_class_iterator(),
CXXRecordDecl::base_class_iterator());
@@ -1246,42 +1322,22 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
if (SubInitList->getNumInits() == 1 &&
IsStringInit(SubInitList->getInit(0), ElemType, SemaRef.Context) ==
SIF_None) {
+ // FIXME: It would be more faithful and no less correct to include an
+ // InitListExpr in the semantic form of the initializer list in this case.
expr = SubInitList->getInit(0);
- } else if (!SemaRef.getLangOpts().CPlusPlus) {
- InitListExpr *InnerStructuredList
- = getStructuredSubobjectInit(IList, Index, ElemType,
- StructuredList, StructuredIndex,
- SubInitList->getSourceRange(), true);
- CheckExplicitInitList(Entity, SubInitList, ElemType,
- InnerStructuredList);
-
- if (!hadError && !VerifyOnly) {
- bool RequiresSecondPass = false;
- FillInEmptyInitializations(Entity, InnerStructuredList,
- RequiresSecondPass, StructuredList,
- StructuredIndex);
- if (RequiresSecondPass && !hadError)
- FillInEmptyInitializations(Entity, InnerStructuredList,
- RequiresSecondPass, StructuredList,
- StructuredIndex);
- }
- ++StructuredIndex;
- ++Index;
- return;
}
- // C++ initialization is handled later.
+ // Nested aggregate initialization and C++ initialization are handled later.
} else if (isa<ImplicitValueInitExpr>(expr)) {
// This happens during template instantiation when we see an InitListExpr
// that we've already checked once.
assert(SemaRef.Context.hasSameType(expr->getType(), ElemType) &&
"found implicit initialization for the wrong type");
- if (!VerifyOnly)
- UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+ UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
++Index;
return;
}
- if (SemaRef.getLangOpts().CPlusPlus) {
+ if (SemaRef.getLangOpts().CPlusPlus || isa<InitListExpr>(expr)) {
// C++ [dcl.init.aggr]p2:
// Each member is copy-initialized from the corresponding
// initializer-clause.
@@ -1289,7 +1345,16 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// FIXME: Better EqualLoc?
InitializationKind Kind =
InitializationKind::CreateCopy(expr->getBeginLoc(), SourceLocation());
- InitializationSequence Seq(SemaRef, Entity, Kind, expr,
+
+ // Vector elements can be initialized from other vectors in which case
+ // we need initialization entity with a type of a vector (and not a vector
+ // element!) initializing multiple vector elements.
+ auto TmpEntity =
+ (ElemType->isExtVectorType() && !Entity.getType()->isExtVectorType())
+ ? InitializedEntity::InitializeTemporary(ElemType)
+ : Entity;
+
+ InitializationSequence Seq(SemaRef, TmpEntity, Kind, expr,
/*TopLevelOfInitList*/ true);
// C++14 [dcl.init.aggr]p13:
@@ -1300,15 +1365,18 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// assignment-expression.
if (Seq || isa<InitListExpr>(expr)) {
if (!VerifyOnly) {
- ExprResult Result =
- Seq.Perform(SemaRef, Entity, Kind, expr);
+ ExprResult Result = Seq.Perform(SemaRef, TmpEntity, Kind, expr);
if (Result.isInvalid())
hadError = true;
UpdateStructuredListElement(StructuredList, StructuredIndex,
Result.getAs<Expr>());
- } else if (!Seq)
+ } else if (!Seq) {
hadError = true;
+ } else if (StructuredList) {
+ UpdateStructuredListElement(StructuredList, StructuredIndex,
+ getDummyInit());
+ }
++Index;
return;
}
@@ -1325,10 +1393,11 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// type here, though.
if (IsStringInit(expr, arrayType, SemaRef.Context) == SIF_None) {
- if (!VerifyOnly) {
+ // FIXME: Should we do this checking in verify-only mode?
+ if (!VerifyOnly)
CheckStringInit(expr, ElemType, arrayType, SemaRef);
+ if (StructuredList)
UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
- }
++Index;
return;
}
@@ -1354,8 +1423,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
hadError = true;
else {
ExprRes = SemaRef.DefaultFunctionArrayLvalueConversion(ExprRes.get());
- if (ExprRes.isInvalid())
- hadError = true;
+ if (ExprRes.isInvalid())
+ hadError = true;
}
UpdateStructuredListElement(StructuredList, StructuredIndex,
ExprRes.getAs<Expr>());
@@ -1380,10 +1449,15 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
++StructuredIndex;
} else {
if (!VerifyOnly) {
- // We cannot initialize this element, so let
- // PerformCopyInitialization produce the appropriate diagnostic.
- SemaRef.PerformCopyInitialization(Entity, SourceLocation(), expr,
- /*TopLevelOfInitList=*/true);
+ // We cannot initialize this element, so let PerformCopyInitialization
+ // produce the appropriate diagnostic. We already checked that this
+ // initialization will fail.
+ ExprResult Copy =
+ SemaRef.PerformCopyInitialization(Entity, SourceLocation(), expr,
+ /*TopLevelOfInitList=*/true);
+ (void)Copy;
+ assert(Copy.isInvalid() &&
+ "expected non-aggregate initialization to fail");
}
hadError = true;
++Index;
@@ -1416,7 +1490,7 @@ void InitListChecker::CheckComplexType(const InitializedEntity &Entity,
<< IList->getSourceRange();
// Initialize the complex number.
- QualType elementType = DeclType->getAs<ComplexType>()->getElementType();
+ QualType elementType = DeclType->castAs<ComplexType>()->getElementType();
InitializedEntity ElementEntity =
InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity);
@@ -1467,17 +1541,18 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
return;
}
+ ExprResult Result;
if (VerifyOnly) {
- if (!SemaRef.CanPerformCopyInitialization(Entity,expr))
- hadError = true;
- ++Index;
- return;
+ if (SemaRef.CanPerformCopyInitialization(Entity, expr))
+ Result = getDummyInit();
+ else
+ Result = ExprError();
+ } else {
+ Result =
+ SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr,
+ /*TopLevelOfInitList=*/true);
}
- ExprResult Result =
- SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr,
- /*TopLevelOfInitList=*/true);
-
Expr *ResultExpr = nullptr;
if (Result.isInvalid())
@@ -1485,8 +1560,9 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
else {
ResultExpr = Result.getAs<Expr>();
- if (ResultExpr != expr) {
+ if (ResultExpr != expr && !VerifyOnly) {
// The type was promoted, update initializer list.
+ // FIXME: Why are we updating the syntactic init list?
IList->setInit(Index, ResultExpr);
}
}
@@ -1528,22 +1604,25 @@ void InitListChecker::CheckReferenceType(const InitializedEntity &Entity,
return;
}
+ ExprResult Result;
if (VerifyOnly) {
- if (!SemaRef.CanPerformCopyInitialization(Entity,expr))
- hadError = true;
- ++Index;
- return;
+ if (SemaRef.CanPerformCopyInitialization(Entity,expr))
+ Result = getDummyInit();
+ else
+ Result = ExprError();
+ } else {
+ Result =
+ SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr,
+ /*TopLevelOfInitList=*/true);
}
- ExprResult Result =
- SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr,
- /*TopLevelOfInitList=*/true);
-
if (Result.isInvalid())
hadError = true;
expr = Result.getAs<Expr>();
- IList->setInit(Index, expr);
+ // FIXME: Why are we updating the syntactic init list?
+ if (!VerifyOnly)
+ IList->setInit(Index, expr);
if (hadError)
++StructuredIndex;
@@ -1557,17 +1636,16 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
- const VectorType *VT = DeclType->getAs<VectorType>();
+ const VectorType *VT = DeclType->castAs<VectorType>();
unsigned maxElements = VT->getNumElements();
unsigned numEltsInit = 0;
QualType elementType = VT->getElementType();
if (Index >= IList->getNumInits()) {
// Make sure the element type can be value-initialized.
- if (VerifyOnly)
- CheckEmptyInitializable(
- InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity),
- IList->getEndLoc());
+ CheckEmptyInitializable(
+ InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity),
+ IList->getEndLoc());
return;
}
@@ -1576,25 +1654,27 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
// instead of breaking it apart (which is doomed to failure anyway).
Expr *Init = IList->getInit(Index);
if (!isa<InitListExpr>(Init) && Init->getType()->isVectorType()) {
+ ExprResult Result;
if (VerifyOnly) {
- if (!SemaRef.CanPerformCopyInitialization(Entity, Init))
- hadError = true;
- ++Index;
- return;
+ if (SemaRef.CanPerformCopyInitialization(Entity, Init))
+ Result = getDummyInit();
+ else
+ Result = ExprError();
+ } else {
+ Result =
+ SemaRef.PerformCopyInitialization(Entity, Init->getBeginLoc(), Init,
+ /*TopLevelOfInitList=*/true);
}
- ExprResult Result =
- SemaRef.PerformCopyInitialization(Entity, Init->getBeginLoc(), Init,
- /*TopLevelOfInitList=*/true);
-
Expr *ResultExpr = nullptr;
if (Result.isInvalid())
hadError = true; // types weren't compatible.
else {
ResultExpr = Result.getAs<Expr>();
- if (ResultExpr != Init) {
+ if (ResultExpr != Init && !VerifyOnly) {
// The type was promoted, update initializer list.
+ // FIXME: Why are we updating the syntactic init list?
IList->setInit(Index, ResultExpr);
}
}
@@ -1613,8 +1693,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
for (unsigned i = 0; i < maxElements; ++i, ++numEltsInit) {
// Don't attempt to go past the end of the init list
if (Index >= IList->getNumInits()) {
- if (VerifyOnly)
- CheckEmptyInitializable(ElementEntity, IList->getEndLoc());
+ CheckEmptyInitializable(ElementEntity, IList->getEndLoc());
break;
}
@@ -1627,7 +1706,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
return;
bool isBigEndian = SemaRef.Context.getTargetInfo().isBigEndian();
- const VectorType *T = Entity.getType()->getAs<VectorType>();
+ const VectorType *T = Entity.getType()->castAs<VectorType>();
if (isBigEndian && (T->getVectorKind() == VectorType::NeonVector ||
T->getVectorKind() == VectorType::NeonPolyVector)) {
// The ability to use vector initializer lists is a GNU vector extension
@@ -1683,7 +1762,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
++numEltsInit;
} else {
QualType VecType;
- const VectorType *IVT = IType->getAs<VectorType>();
+ const VectorType *IVT = IType->castAs<VectorType>();
unsigned numIElts = IVT->getNumElements();
if (IType->isExtVectorType())
@@ -1757,8 +1836,10 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
// of the structured initializer list doesn't match exactly,
// because doing so would involve allocating one character
// constant for each string.
- if (!VerifyOnly) {
+ // FIXME: Should we do these checks in verify-only mode too?
+ if (!VerifyOnly)
CheckStringInit(IList->getInit(Index), DeclType, arrayType, SemaRef);
+ if (StructuredList) {
UpdateStructuredListElement(StructuredList, StructuredIndex,
IList->getInit(Index));
StructuredList->resizeInits(SemaRef.Context, StructuredIndex);
@@ -1854,15 +1935,14 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
SemaRef.Diag(IList->getBeginLoc(), diag::ext_typecheck_zero_array_size);
}
- DeclType = SemaRef.Context.getConstantArrayType(elementType, maxElements,
- ArrayType::Normal, 0);
+ DeclType = SemaRef.Context.getConstantArrayType(
+ elementType, maxElements, nullptr, ArrayType::Normal, 0);
}
- if (!hadError && VerifyOnly) {
+ if (!hadError) {
// If there are any members of the array that get value-initialized, check
// that is possible. That happens if we know the bound and don't have
// enough elements, or if we're performing an array new with an unknown
// bound.
- // FIXME: This needs to detect holes left by designated initializers too.
if ((maxElementsKnown && elementIndex < maxElements) ||
Entity.isVariableLengthArrayNew())
CheckEmptyInitializable(
@@ -1915,7 +1995,7 @@ void InitListChecker::CheckStructUnionTypes(
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredList, unsigned &StructuredIndex,
bool TopLevelObject) {
- RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl();
+ RecordDecl *structDecl = DeclType->castAs<RecordType>()->getDecl();
// If the record is invalid, some of it's members are invalid. To avoid
// confusion, we forgo checking the intializer for the entire record.
@@ -1927,7 +2007,7 @@ void InitListChecker::CheckStructUnionTypes(
}
if (DeclType->isUnionType() && IList->getNumInits() == 0) {
- RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl();
if (!VerifyOnly)
for (FieldDecl *FD : RD->fields()) {
@@ -1939,8 +2019,9 @@ void InitListChecker::CheckStructUnionTypes(
}
// If there's a default initializer, use it.
- if (isa<CXXRecordDecl>(RD) && cast<CXXRecordDecl>(RD)->hasInClassInitializer()) {
- if (VerifyOnly)
+ if (isa<CXXRecordDecl>(RD) &&
+ cast<CXXRecordDecl>(RD)->hasInClassInitializer()) {
+ if (!StructuredList)
return;
for (RecordDecl::field_iterator FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
@@ -1957,11 +2038,10 @@ void InitListChecker::CheckStructUnionTypes(
for (RecordDecl::field_iterator FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
if (!Field->isUnnamedBitfield()) {
- if (VerifyOnly)
- CheckEmptyInitializable(
- InitializedEntity::InitializeMember(*Field, &Entity),
- IList->getEndLoc());
- else
+ CheckEmptyInitializable(
+ InitializedEntity::InitializeMember(*Field, &Entity),
+ IList->getEndLoc());
+ if (StructuredList)
StructuredList->setInitializedFieldInUnion(*Field);
break;
}
@@ -1987,7 +2067,7 @@ void InitListChecker::CheckStructUnionTypes(
CheckSubElementType(BaseEntity, IList, Base.getType(), Index,
StructuredList, StructuredIndex);
InitializedSomething = true;
- } else if (VerifyOnly) {
+ } else {
CheckEmptyInitializable(BaseEntity, InitLoc);
}
@@ -2002,7 +2082,7 @@ void InitListChecker::CheckStructUnionTypes(
// anything except look at designated initializers; That's okay,
// because an error should get printed out elsewhere. It might be
// worthwhile to skip over the rest of the initializer, though.
- RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl();
RecordDecl::field_iterator FieldEnd = RD->field_end();
bool CheckForMissingFields =
!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts());
@@ -2095,7 +2175,7 @@ void InitListChecker::CheckStructUnionTypes(
StructuredList, StructuredIndex);
InitializedSomething = true;
- if (DeclType->isUnionType() && !VerifyOnly) {
+ if (DeclType->isUnionType() && StructuredList) {
// Initialize the first field within the union.
StructuredList->setInitializedFieldInUnion(*Field);
}
@@ -2119,10 +2199,10 @@ void InitListChecker::CheckStructUnionTypes(
}
}
- // Check that any remaining fields can be value-initialized.
- if (VerifyOnly && Field != FieldEnd && !DeclType->isUnionType() &&
+ // Check that any remaining fields can be value-initialized if we're not
+ // building a structured list. (If we are, we'll check this later.)
+ if (!StructuredList && Field != FieldEnd && !DeclType->isUnionType() &&
!Field->getType()->isIncompleteArrayType()) {
- // FIXME: Should check for holes left by designated initializers too.
for (; Field != FieldEnd && !hadError; ++Field) {
if (!Field->isUnnamedBitfield() && !Field->hasInClassInitializer())
CheckEmptyInitializable(
@@ -2227,7 +2307,7 @@ class FieldInitializerValidatorCCC final : public CorrectionCandidateCallback {
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<FieldInitializerValidatorCCC>(*this);
+ return std::make_unique<FieldInitializerValidatorCCC>(*this);
}
private:
@@ -2257,7 +2337,9 @@ class FieldInitializerValidatorCCC final : public CorrectionCandidateCallback {
///
/// @param NextField If non-NULL and the first designator in @p DIE is
/// a field, this will be set to the field declaration corresponding
-/// to the field named by the designator.
+/// to the field named by the designator. On input, this is expected to be
+/// the next field that would be initialized in the absence of designation,
+/// if the complete object being initialized is a struct.
///
/// @param NextElementIndex If non-NULL and the first designator in @p
/// DIE is an array designator or GNU array-range designator, this
@@ -2285,6 +2367,29 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
bool FinishSubobjectInit,
bool TopLevelObject) {
if (DesigIdx == DIE->size()) {
+ // C++20 designated initialization can result in direct-list-initialization
+ // of the designated subobject. This is the only way that we can end up
+ // performing direct initialization as part of aggregate initialization, so
+ // it needs special handling.
+ if (DIE->isDirectInit()) {
+ Expr *Init = DIE->getInit();
+ assert(isa<InitListExpr>(Init) &&
+ "designator result in direct non-list initialization?");
+ InitializationKind Kind = InitializationKind::CreateDirectList(
+ DIE->getBeginLoc(), Init->getBeginLoc(), Init->getEndLoc());
+ InitializationSequence Seq(SemaRef, Entity, Kind, Init,
+ /*TopLevelOfInitList*/ true);
+ if (StructuredList) {
+ ExprResult Result = VerifyOnly
+ ? getDummyInit()
+ : Seq.Perform(SemaRef, Entity, Kind, Init);
+ UpdateStructuredListElement(StructuredList, StructuredIndex,
+ Result.get());
+ }
+ ++Index;
+ return !Seq;
+ }
+
// Check the actual initialization for the designated object type.
bool prevHadError = hadError;
@@ -2308,14 +2413,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
DesignatedInitExpr::Designator *D = DIE->getDesignator(DesigIdx);
bool IsFirstDesignator = (DesigIdx == 0);
- if (!VerifyOnly) {
- assert((IsFirstDesignator || StructuredList) &&
- "Need a non-designated initializer list to start from");
-
+ if (IsFirstDesignator ? FullyStructuredList : StructuredList) {
// Determine the structural initializer list that corresponds to the
// current subobject.
if (IsFirstDesignator)
- StructuredList = SyntacticToSemantic.lookup(IList);
+ StructuredList = FullyStructuredList;
else {
Expr *ExistingInit = StructuredIndex < StructuredList->getNumInits() ?
StructuredList->getInit(StructuredIndex) : nullptr;
@@ -2329,48 +2431,42 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
else if (InitListExpr *Result = dyn_cast<InitListExpr>(ExistingInit))
StructuredList = Result;
else {
- if (DesignatedInitUpdateExpr *E =
- dyn_cast<DesignatedInitUpdateExpr>(ExistingInit))
- StructuredList = E->getUpdater();
- else {
- DesignatedInitUpdateExpr *DIUE = new (SemaRef.Context)
- DesignatedInitUpdateExpr(SemaRef.Context, D->getBeginLoc(),
- ExistingInit, DIE->getEndLoc());
- StructuredList->updateInit(SemaRef.Context, StructuredIndex, DIUE);
- StructuredList = DIUE->getUpdater();
- }
-
- // We need to check on source range validity because the previous
- // initializer does not have to be an explicit initializer. e.g.,
+ // We are creating an initializer list that initializes the
+ // subobjects of the current object, but there was already an
+ // initialization that completely initialized the current
+ // subobject, e.g., by a compound literal:
//
- // struct P { int a, b; };
- // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 };
+ // struct X { int a, b; };
+ // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
//
- // There is an overwrite taking place because the first braced initializer
- // list "{ .a = 2 }" already provides value for .p.b (which is zero).
- if (ExistingInit->getSourceRange().isValid()) {
- // We are creating an initializer list that initializes the
- // subobjects of the current object, but there was already an
- // initialization that completely initialized the current
- // subobject, e.g., by a compound literal:
- //
- // struct X { int a, b; };
- // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
- //
- // Here, xs[0].a == 0 and xs[0].b == 3, since the second,
- // designated initializer re-initializes the whole
- // subobject [0], overwriting previous initializers.
- SemaRef.Diag(D->getBeginLoc(),
- diag::warn_subobject_initializer_overrides)
- << SourceRange(D->getBeginLoc(), DIE->getEndLoc());
-
- SemaRef.Diag(ExistingInit->getBeginLoc(),
- diag::note_previous_initializer)
- << /*FIXME:has side effects=*/0 << ExistingInit->getSourceRange();
+ // Here, xs[0].a == 1 and xs[0].b == 3, since the second,
+ // designated initializer re-initializes only its current object
+ // subobject [0].b.
+ diagnoseInitOverride(ExistingInit,
+ SourceRange(D->getBeginLoc(), DIE->getEndLoc()),
+ /*FullyOverwritten=*/false);
+
+ if (!VerifyOnly) {
+ if (DesignatedInitUpdateExpr *E =
+ dyn_cast<DesignatedInitUpdateExpr>(ExistingInit))
+ StructuredList = E->getUpdater();
+ else {
+ DesignatedInitUpdateExpr *DIUE = new (SemaRef.Context)
+ DesignatedInitUpdateExpr(SemaRef.Context, D->getBeginLoc(),
+ ExistingInit, DIE->getEndLoc());
+ StructuredList->updateInit(SemaRef.Context, StructuredIndex, DIUE);
+ StructuredList = DIUE->getUpdater();
+ }
+ } else {
+ // We don't need to track the structured representation of a
+ // designated init update of an already-fully-initialized object in
+ // verify-only mode. The only reason we would need the structure is
+ // to determine where the uninitialized "holes" are, and in this
+ // case, we know there aren't any and we can't introduce any.
+ StructuredList = nullptr;
}
}
}
- assert(StructuredList && "Expected a structured initializer list");
}
if (D->isFieldDesignator()) {
@@ -2453,10 +2549,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
}
}
- unsigned FieldIndex = 0;
-
+ unsigned NumBases = 0;
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
- FieldIndex = CXXRD->getNumBases();
+ NumBases = CXXRD->getNumBases();
+
+ unsigned FieldIndex = NumBases;
for (auto *FI : RT->getDecl()->fields()) {
if (FI->isUnnamedBitfield())
@@ -2475,7 +2572,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// the initializer list.
if (RT->getDecl()->isUnion()) {
FieldIndex = 0;
- if (!VerifyOnly) {
+ if (StructuredList) {
FieldDecl *CurrentField = StructuredList->getInitializedFieldInUnion();
if (CurrentField && !declaresSameEntity(CurrentField, *Field)) {
assert(StructuredList->getNumInits() == 1
@@ -2484,13 +2581,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
Expr *ExistingInit = StructuredList->getInit(0);
if (ExistingInit) {
// We're about to throw away an initializer, emit warning.
- SemaRef.Diag(D->getFieldLoc(),
- diag::warn_initializer_overrides)
- << D->getSourceRange();
- SemaRef.Diag(ExistingInit->getBeginLoc(),
- diag::note_previous_initializer)
- << /*FIXME:has side effects=*/0
- << ExistingInit->getSourceRange();
+ diagnoseInitOverride(
+ ExistingInit, SourceRange(D->getBeginLoc(), DIE->getEndLoc()));
}
// remove existing initializer
@@ -2513,16 +2605,63 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
return true;
}
- if (!VerifyOnly) {
- // Update the designator with the field declaration.
- D->setField(*Field);
+ // C++20 [dcl.init.list]p3:
+ // The ordered identifiers in the designators of the designated-
+ // initializer-list shall form a subsequence of the ordered identifiers
+ // in the direct non-static data members of T.
+ //
+ // Note that this is not a condition on forming the aggregate
+ // initialization, only on actually performing initialization,
+ // so it is not checked in VerifyOnly mode.
+ //
+ // FIXME: This is the only reordering diagnostic we produce, and it only
+ // catches cases where we have a top-level field designator that jumps
+ // backwards. This is the only such case that is reachable in an
+ // otherwise-valid C++20 program, so is the only case that's required for
+ // conformance, but for consistency, we should diagnose all the other
+ // cases where a designator takes us backwards too.
+ if (IsFirstDesignator && !VerifyOnly && SemaRef.getLangOpts().CPlusPlus &&
+ NextField &&
+ (*NextField == RT->getDecl()->field_end() ||
+ (*NextField)->getFieldIndex() > Field->getFieldIndex() + 1)) {
+ // Find the field that we just initialized.
+ FieldDecl *PrevField = nullptr;
+ for (auto FI = RT->getDecl()->field_begin();
+ FI != RT->getDecl()->field_end(); ++FI) {
+ if (FI->isUnnamedBitfield())
+ continue;
+ if (*NextField != RT->getDecl()->field_end() &&
+ declaresSameEntity(*FI, **NextField))
+ break;
+ PrevField = *FI;
+ }
- // Make sure that our non-designated initializer list has space
- // for a subobject corresponding to this field.
- if (FieldIndex >= StructuredList->getNumInits())
- StructuredList->resizeInits(SemaRef.Context, FieldIndex + 1);
+ if (PrevField &&
+ PrevField->getFieldIndex() > KnownField->getFieldIndex()) {
+ SemaRef.Diag(DIE->getBeginLoc(), diag::ext_designated_init_reordered)
+ << KnownField << PrevField << DIE->getSourceRange();
+
+ unsigned OldIndex = NumBases + PrevField->getFieldIndex();
+ if (StructuredList && OldIndex <= StructuredList->getNumInits()) {
+ if (Expr *PrevInit = StructuredList->getInit(OldIndex)) {
+ SemaRef.Diag(PrevInit->getBeginLoc(),
+ diag::note_previous_field_init)
+ << PrevField << PrevInit->getSourceRange();
+ }
+ }
+ }
}
+
+ // Update the designator with the field declaration.
+ if (!VerifyOnly)
+ D->setField(*Field);
+
+ // Make sure that our non-designated initializer list has space
+ // for a subobject corresponding to this field.
+ if (StructuredList && FieldIndex >= StructuredList->getNumInits())
+ StructuredList->resizeInits(SemaRef.Context, FieldIndex + 1);
+
// This designator names a flexible array member.
if (Field->getType()->isIncompleteArrayType()) {
bool Invalid = false;
@@ -2707,7 +2846,13 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
DesignatedEndIndex.setIsUnsigned(true);
}
- if (!VerifyOnly && StructuredList->isStringLiteralInit()) {
+ bool IsStringLiteralInitUpdate =
+ StructuredList && StructuredList->isStringLiteralInit();
+ if (IsStringLiteralInitUpdate && VerifyOnly) {
+ // We're just verifying an update to a string literal init. We don't need
+ // to split the string up into individual characters to do that.
+ StructuredList = nullptr;
+ } else if (IsStringLiteralInitUpdate) {
// We're modifying a string literal init; we have to decompose the string
// so we can modify the individual characters.
ASTContext &Context = SemaRef.Context;
@@ -2767,7 +2912,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// Make sure that our non-designated initializer list has space
// for a subobject corresponding to this array element.
- if (!VerifyOnly &&
+ if (StructuredList &&
DesignatedEndIndex.getZExtValue() >= StructuredList->getNumInits())
StructuredList->resizeInits(SemaRef.Context,
DesignatedEndIndex.getZExtValue() + 1);
@@ -2829,12 +2974,11 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
unsigned StructuredIndex,
SourceRange InitRange,
bool IsFullyOverwritten) {
- if (VerifyOnly)
- return nullptr; // No structured list in verification-only mode.
- Expr *ExistingInit = nullptr;
if (!StructuredList)
- ExistingInit = SyntacticToSemantic.lookup(IList);
- else if (StructuredIndex < StructuredList->getNumInits())
+ return nullptr;
+
+ Expr *ExistingInit = nullptr;
+ if (StructuredIndex < StructuredList->getNumInits())
ExistingInit = StructuredList->getInit(StructuredIndex);
if (InitListExpr *Result = dyn_cast_or_null<InitListExpr>(ExistingInit))
@@ -2853,21 +2997,46 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
// We are creating an initializer list that initializes the
// subobjects of the current object, but there was already an
// initialization that completely initialized the current
- // subobject, e.g., by a compound literal:
+ // subobject:
//
// struct X { int a, b; };
+ // struct X xs[] = { [0] = { 1, 2 }, [0].b = 3 };
+ //
+ // Here, xs[0].a == 1 and xs[0].b == 3, since the second,
+ // designated initializer overwrites the [0].b initializer
+ // from the prior initialization.
+ //
+ // When the existing initializer is an expression rather than an
+ // initializer list, we cannot decompose and update it in this way.
+ // For example:
+ //
// struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
//
- // Here, xs[0].a == 0 and xs[0].b == 3, since the second,
- // designated initializer re-initializes the whole
- // subobject [0], overwriting previous initializers.
- SemaRef.Diag(InitRange.getBegin(),
- diag::warn_subobject_initializer_overrides)
- << InitRange;
- SemaRef.Diag(ExistingInit->getBeginLoc(), diag::note_previous_initializer)
- << /*FIXME:has side effects=*/0 << ExistingInit->getSourceRange();
+ // This case is handled by CheckDesignatedInitializer.
+ diagnoseInitOverride(ExistingInit, InitRange);
}
+ unsigned ExpectedNumInits = 0;
+ if (Index < IList->getNumInits()) {
+ if (auto *Init = dyn_cast_or_null<InitListExpr>(IList->getInit(Index)))
+ ExpectedNumInits = Init->getNumInits();
+ else
+ ExpectedNumInits = IList->getNumInits() - Index;
+ }
+
+ InitListExpr *Result =
+ createInitListExpr(CurrentObjectType, InitRange, ExpectedNumInits);
+
+ // Link this new initializer list into the structured initializer
+ // lists.
+ StructuredList->updateInit(SemaRef.Context, StructuredIndex, Result);
+ return Result;
+}
+
+InitListExpr *
+InitListChecker::createInitListExpr(QualType CurrentObjectType,
+ SourceRange InitRange,
+ unsigned ExpectedNumInits) {
InitListExpr *Result
= new (SemaRef.Context) InitListExpr(SemaRef.Context,
InitRange.getBegin(), None,
@@ -2880,17 +3049,6 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
// Pre-allocate storage for the structured initializer list.
unsigned NumElements = 0;
- unsigned NumInits = 0;
- bool GotNumInits = false;
- if (!StructuredList) {
- NumInits = IList->getNumInits();
- GotNumInits = true;
- } else if (Index < IList->getNumInits()) {
- if (InitListExpr *SubList = dyn_cast<InitListExpr>(IList->getInit(Index))) {
- NumInits = SubList->getNumInits();
- GotNumInits = true;
- }
- }
if (const ArrayType *AType
= SemaRef.Context.getAsArrayType(CurrentObjectType)) {
@@ -2898,30 +3056,17 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
NumElements = CAType->getSize().getZExtValue();
// Simple heuristic so that we don't allocate a very large
// initializer with many empty entries at the end.
- if (GotNumInits && NumElements > NumInits)
+ if (NumElements > ExpectedNumInits)
NumElements = 0;
}
- } else if (const VectorType *VType = CurrentObjectType->getAs<VectorType>())
+ } else if (const VectorType *VType = CurrentObjectType->getAs<VectorType>()) {
NumElements = VType->getNumElements();
- else if (const RecordType *RType = CurrentObjectType->getAs<RecordType>()) {
- RecordDecl *RDecl = RType->getDecl();
- if (RDecl->isUnion())
- NumElements = 1;
- else
- NumElements = std::distance(RDecl->field_begin(), RDecl->field_end());
+ } else if (CurrentObjectType->isRecordType()) {
+ NumElements = numStructUnionElements(CurrentObjectType);
}
Result->reserveInits(SemaRef.Context, NumElements);
- // Link this new initializer list into the structured initializer
- // lists.
- if (StructuredList)
- StructuredList->updateInit(SemaRef.Context, StructuredIndex, Result);
- else {
- Result->setSyntacticForm(IList);
- SyntacticToSemantic[IList] = Result;
- }
-
return Result;
}
@@ -2937,24 +3082,23 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
if (Expr *PrevInit = StructuredList->updateInit(SemaRef.Context,
StructuredIndex, expr)) {
// This initializer overwrites a previous initializer. Warn.
- // We need to check on source range validity because the previous
- // initializer does not have to be an explicit initializer.
- // struct P { int a, b; };
- // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 };
- // There is an overwrite taking place because the first braced initializer
- // list "{ .a = 2 }' already provides value for .p.b (which is zero).
- if (PrevInit->getSourceRange().isValid()) {
- SemaRef.Diag(expr->getBeginLoc(), diag::warn_initializer_overrides)
- << expr->getSourceRange();
-
- SemaRef.Diag(PrevInit->getBeginLoc(), diag::note_previous_initializer)
- << /*FIXME:has side effects=*/0 << PrevInit->getSourceRange();
- }
+ diagnoseInitOverride(PrevInit, expr->getSourceRange());
}
++StructuredIndex;
}
+/// Determine whether we can perform aggregate initialization for the purposes
+/// of overload resolution.
+bool Sema::CanPerformAggregateInitializationForOverloadResolution(
+ const InitializedEntity &Entity, InitListExpr *From) {
+ QualType Type = Entity.getType();
+ InitListChecker Check(*this, Entity, From, Type, /*VerifyOnly=*/true,
+ /*TreatUnavailableAsInvalid=*/false,
+ /*InOverloadResolution=*/true);
+ return !Check.HadError();
+}
+
/// Check that the given Index expression is a valid array designator
/// value. This is essentially just a wrapper around
/// VerifyIntegerConstantExpression that also checks for negative values
@@ -2980,7 +3124,7 @@ CheckArrayDesignatorExpr(Sema &S, Expr *Index, llvm::APSInt &Value) {
}
ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
- SourceLocation Loc,
+ SourceLocation EqualOrColonLoc,
bool GNUSyntax,
ExprResult Init) {
typedef DesignatedInitExpr::Designator ASTDesignator;
@@ -3065,17 +3209,9 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
// Clear out the expressions within the designation.
Desig.ClearExprs(*this);
- DesignatedInitExpr *DIE
- = DesignatedInitExpr::Create(Context,
- Designators,
- InitExpressions, Loc, GNUSyntax,
- Init.getAs<Expr>());
-
- if (!getLangOpts().C99)
- Diag(DIE->getBeginLoc(), diag::ext_designated_init)
- << DIE->getSourceRange();
-
- return DIE;
+ return DesignatedInitExpr::Create(Context, Designators, InitExpressions,
+ EqualOrColonLoc, GNUSyntax,
+ Init.getAs<Expr>());
}
//===----------------------------------------------------------------------===//
@@ -3691,9 +3827,10 @@ static bool TryInitializerListConstruction(Sema &S,
// Try initializing a temporary array from the init list.
QualType ArrayType = S.Context.getConstantArrayType(
- E.withConst(), llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
- List->getNumInits()),
- clang::ArrayType::Normal, 0);
+ E.withConst(),
+ llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
+ List->getNumInits()),
+ nullptr, clang::ArrayType::Normal, 0);
InitializedEntity HiddenArray =
InitializedEntity::InitializeTemporary(ArrayType);
InitializationKind Kind = InitializationKind::CreateDirectList(
@@ -4070,7 +4207,7 @@ static void TryReferenceListInitialization(Sema &S,
}
QualType DestType = Entity.getType();
- QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
+ QualType cv1T1 = DestType->castAs<ReferenceType>()->getPointeeType();
Qualifiers T1Quals;
QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals);
@@ -4092,10 +4229,10 @@ static void TryReferenceListInitialization(Sema &S,
return;
SourceLocation DeclLoc = Initializer->getBeginLoc();
- bool dummy1, dummy2, dummy3;
+ bool dummy1, dummy2, dummy3, dummy4;
Sema::ReferenceCompareResult RefRelationship
= S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, dummy1,
- dummy2, dummy3);
+ dummy2, dummy3, dummy4);
if (RefRelationship >= Sema::Ref_Related) {
// Try to bind the reference here.
TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
@@ -4327,7 +4464,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
Expr *Initializer, bool AllowRValues, bool IsLValueRef,
InitializationSequence &Sequence) {
QualType DestType = Entity.getType();
- QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
+ QualType cv1T1 = DestType->castAs<ReferenceType>()->getPointeeType();
QualType T1 = cv1T1.getUnqualifiedType();
QualType cv2T2 = Initializer->getType();
QualType T2 = cv2T2.getUnqualifiedType();
@@ -4335,13 +4472,15 @@ static OverloadingResult TryRefInitWithConversionFunction(
bool DerivedToBase;
bool ObjCConversion;
bool ObjCLifetimeConversion;
- assert(!S.CompareReferenceRelationship(Initializer->getBeginLoc(), T1, T2,
- DerivedToBase, ObjCConversion,
- ObjCLifetimeConversion) &&
+ bool FunctionConversion;
+ assert(!S.CompareReferenceRelationship(
+ Initializer->getBeginLoc(), T1, T2, DerivedToBase, ObjCConversion,
+ ObjCLifetimeConversion, FunctionConversion) &&
"Must have incompatible references when binding via conversion");
(void)DerivedToBase;
(void)ObjCConversion;
(void)ObjCLifetimeConversion;
+ (void)FunctionConversion;
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
@@ -4468,10 +4607,11 @@ static OverloadingResult TryRefInitWithConversionFunction(
bool NewDerivedToBase = false;
bool NewObjCConversion = false;
bool NewObjCLifetimeConversion = false;
- Sema::ReferenceCompareResult NewRefRelationship
- = S.CompareReferenceRelationship(DeclLoc, T1, cv3T3,
- NewDerivedToBase, NewObjCConversion,
- NewObjCLifetimeConversion);
+ bool NewFunctionConversion = false;
+ Sema::ReferenceCompareResult NewRefRelationship =
+ S.CompareReferenceRelationship(
+ DeclLoc, T1, cv3T3, NewDerivedToBase, NewObjCConversion,
+ NewObjCLifetimeConversion, NewFunctionConversion);
// Add the final conversion sequence, if necessary.
if (NewRefRelationship == Sema::Ref_Incompatible) {
@@ -4505,6 +4645,8 @@ static OverloadingResult TryRefInitWithConversionFunction(
Sequence.AddDerivedToBaseCastStep(cv1T1, VK);
else if (NewObjCConversion)
Sequence.AddObjCObjectConversionStep(cv1T1);
+ else if (NewFunctionConversion)
+ Sequence.AddQualificationConversionStep(cv1T1, VK);
return OR_Success;
}
@@ -4520,7 +4662,7 @@ static void TryReferenceInitialization(Sema &S,
Expr *Initializer,
InitializationSequence &Sequence) {
QualType DestType = Entity.getType();
- QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
+ QualType cv1T1 = DestType->castAs<ReferenceType>()->getPointeeType();
Qualifiers T1Quals;
QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals);
QualType cv2T2 = Initializer->getType();
@@ -4564,10 +4706,11 @@ static void TryReferenceInitializationCore(Sema &S,
bool DerivedToBase = false;
bool ObjCConversion = false;
bool ObjCLifetimeConversion = false;
+ bool FunctionConversion = false;
Expr::Classification InitCategory = Initializer->Classify(S.Context);
- Sema::ReferenceCompareResult RefRelationship
- = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase,
- ObjCConversion, ObjCLifetimeConversion);
+ Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(
+ DeclLoc, cv1T1, cv2T2, DerivedToBase, ObjCConversion,
+ ObjCLifetimeConversion, FunctionConversion);
// C++0x [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression of type
@@ -4598,6 +4741,8 @@ static void TryReferenceInitializationCore(Sema &S,
Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue);
else if (ObjCConversion)
Sequence.AddObjCObjectConversionStep(cv1T1);
+ else if (FunctionConversion)
+ Sequence.AddQualificationConversionStep(cv1T1, VK_LValue);
// We only create a temporary here when binding a reference to a
// bit-field or vector element. Those cases are't supposed to be
@@ -6233,8 +6378,11 @@ PerformConstructorInitialization(Sema &S,
// the definition for completely trivial constructors.
assert(Constructor->getParent() && "No parent class for constructor.");
if (Constructor->isDefaulted() && Constructor->isDefaultConstructor() &&
- Constructor->isTrivial() && !Constructor->isUsed(false))
- S.DefineImplicitDefaultConstructor(Loc, Constructor);
+ Constructor->isTrivial() && !Constructor->isUsed(false)) {
+ S.runWithSufficientStackSpace(Loc, [&] {
+ S.DefineImplicitDefaultConstructor(Loc, Constructor);
+ });
+ }
}
ExprResult CurInit((Expr *)nullptr);
@@ -6505,6 +6653,7 @@ struct IndirectLocalPathEntry {
VarInit,
LValToRVal,
LifetimeBoundCall,
+ GslPointerInit
} Kind;
Expr *E;
const Decl *D = nullptr;
@@ -6543,11 +6692,138 @@ static bool pathContainsInit(IndirectLocalPath &Path) {
static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
Expr *Init, LocalVisitor Visit,
- bool RevisitSubinits);
+ bool RevisitSubinits,
+ bool EnableLifetimeWarnings);
static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
Expr *Init, ReferenceKind RK,
- LocalVisitor Visit);
+ LocalVisitor Visit,
+ bool EnableLifetimeWarnings);
+
+template <typename T> static bool isRecordWithAttr(QualType Type) {
+ if (auto *RD = Type->getAsCXXRecordDecl())
+ return RD->hasAttr<T>();
+ return false;
+}
+
+// Decl::isInStdNamespace will return false for iterators in some STL
+// implementations due to them being defined in a namespace outside of the std
+// namespace.
+static bool isInStlNamespace(const Decl *D) {
+ const DeclContext *DC = D->getDeclContext();
+ if (!DC)
+ return false;
+ if (const auto *ND = dyn_cast<NamespaceDecl>(DC))
+ if (const IdentifierInfo *II = ND->getIdentifier()) {
+ StringRef Name = II->getName();
+ if (Name.size() >= 2 && Name.front() == '_' &&
+ (Name[1] == '_' || isUppercase(Name[1])))
+ return true;
+ }
+
+ return DC->isStdNamespace();
+}
+
+static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {
+ if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee))
+ if (isRecordWithAttr<PointerAttr>(Conv->getConversionType()))
+ return true;
+ if (!isInStlNamespace(Callee->getParent()))
+ return false;
+ if (!isRecordWithAttr<PointerAttr>(Callee->getThisObjectType()) &&
+ !isRecordWithAttr<OwnerAttr>(Callee->getThisObjectType()))
+ return false;
+ if (Callee->getReturnType()->isPointerType() ||
+ isRecordWithAttr<PointerAttr>(Callee->getReturnType())) {
+ if (!Callee->getIdentifier())
+ return false;
+ return llvm::StringSwitch<bool>(Callee->getName())
+ .Cases("begin", "rbegin", "cbegin", "crbegin", true)
+ .Cases("end", "rend", "cend", "crend", true)
+ .Cases("c_str", "data", "get", true)
+ // Map and set types.
+ .Cases("find", "equal_range", "lower_bound", "upper_bound", true)
+ .Default(false);
+ } else if (Callee->getReturnType()->isReferenceType()) {
+ if (!Callee->getIdentifier()) {
+ auto OO = Callee->getOverloadedOperator();
+ return OO == OverloadedOperatorKind::OO_Subscript ||
+ OO == OverloadedOperatorKind::OO_Star;
+ }
+ return llvm::StringSwitch<bool>(Callee->getName())
+ .Cases("front", "back", "at", "top", "value", true)
+ .Default(false);
+ }
+ return false;
+}
+
+static bool shouldTrackFirstArgument(const FunctionDecl *FD) {
+ if (!FD->getIdentifier() || FD->getNumParams() != 1)
+ return false;
+ const auto *RD = FD->getParamDecl(0)->getType()->getPointeeCXXRecordDecl();
+ if (!FD->isInStdNamespace() || !RD || !RD->isInStdNamespace())
+ return false;
+ if (!isRecordWithAttr<PointerAttr>(QualType(RD->getTypeForDecl(), 0)) &&
+ !isRecordWithAttr<OwnerAttr>(QualType(RD->getTypeForDecl(), 0)))
+ return false;
+ if (FD->getReturnType()->isPointerType() ||
+ isRecordWithAttr<PointerAttr>(FD->getReturnType())) {
+ return llvm::StringSwitch<bool>(FD->getName())
+ .Cases("begin", "rbegin", "cbegin", "crbegin", true)
+ .Cases("end", "rend", "cend", "crend", true)
+ .Case("data", true)
+ .Default(false);
+ } else if (FD->getReturnType()->isReferenceType()) {
+ return llvm::StringSwitch<bool>(FD->getName())
+ .Cases("get", "any_cast", true)
+ .Default(false);
+ }
+ return false;
+}
+
+static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
+ LocalVisitor Visit) {
+ auto VisitPointerArg = [&](const Decl *D, Expr *Arg) {
+ // We are not interested in the temporary base objects of gsl Pointers:
+ // Temp().ptr; // Here ptr might not dangle.
+ if (isa<MemberExpr>(Arg->IgnoreImpCasts()))
+ return;
+ Path.push_back({IndirectLocalPathEntry::GslPointerInit, Arg, D});
+ if (Arg->isGLValue())
+ visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding,
+ Visit,
+ /*EnableLifetimeWarnings=*/true);
+ else
+ visitLocalsRetainedByInitializer(Path, Arg, Visit, true,
+ /*EnableLifetimeWarnings=*/true);
+ Path.pop_back();
+ };
+
+ if (auto *MCE = dyn_cast<CXXMemberCallExpr>(Call)) {
+ const auto *MD = cast_or_null<CXXMethodDecl>(MCE->getDirectCallee());
+ if (MD && shouldTrackImplicitObjectArg(MD))
+ VisitPointerArg(MD, MCE->getImplicitObjectArgument());
+ return;
+ } else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(Call)) {
+ FunctionDecl *Callee = OCE->getDirectCallee();
+ if (Callee && Callee->isCXXInstanceMember() &&
+ shouldTrackImplicitObjectArg(cast<CXXMethodDecl>(Callee)))
+ VisitPointerArg(Callee, OCE->getArg(0));
+ return;
+ } else if (auto *CE = dyn_cast<CallExpr>(Call)) {
+ FunctionDecl *Callee = CE->getDirectCallee();
+ if (Callee && shouldTrackFirstArgument(Callee))
+ VisitPointerArg(Callee, CE->getArg(0));
+ return;
+ }
+
+ if (auto *CCE = dyn_cast<CXXConstructExpr>(Call)) {
+ const auto *Ctor = CCE->getConstructor();
+ const CXXRecordDecl *RD = Ctor->getParent();
+ if (CCE->getNumArgs() > 0 && RD->hasAttr<PointerAttr>())
+ VisitPointerArg(Ctor->getParamDecl(0), CCE->getArgs()[0]);
+ }
+}
static bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) {
const TypeSourceInfo *TSI = FD->getTypeSourceInfo();
@@ -6594,9 +6870,11 @@ static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call,
Path.push_back({IndirectLocalPathEntry::LifetimeBoundCall, Arg, D});
if (Arg->isGLValue())
visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding,
- Visit);
+ Visit,
+ /*EnableLifetimeWarnings=*/false);
else
- visitLocalsRetainedByInitializer(Path, Arg, Visit, true);
+ visitLocalsRetainedByInitializer(Path, Arg, Visit, true,
+ /*EnableLifetimeWarnings=*/false);
Path.pop_back();
};
@@ -6615,7 +6893,8 @@ static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call,
/// glvalue expression \c Init.
static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
Expr *Init, ReferenceKind RK,
- LocalVisitor Visit) {
+ LocalVisitor Visit,
+ bool EnableLifetimeWarnings) {
RevertToOldSizeRAII RAII(Path);
// Walk past any constructs which we can lifetime-extend across.
@@ -6652,7 +6931,8 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
else
// We can't lifetime extend through this but we might still find some
// retained temporaries.
- return visitLocalsRetainedByInitializer(Path, Init, Visit, true);
+ return visitLocalsRetainedByInitializer(Path, Init, Visit, true,
+ EnableLifetimeWarnings);
}
// Step into CXXDefaultInitExprs so we can diagnose cases where a
@@ -6667,11 +6947,14 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) {
if (Visit(Path, Local(MTE), RK))
visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(), Visit,
- true);
+ true, EnableLifetimeWarnings);
}
- if (isa<CallExpr>(Init))
+ if (isa<CallExpr>(Init)) {
+ if (EnableLifetimeWarnings)
+ handleGslAnnotatedTypes(Path, Init, Visit);
return visitLifetimeBoundArguments(Path, Init, Visit);
+ }
switch (Init->getStmtClass()) {
case Stmt::DeclRefExprClass: {
@@ -6690,7 +6973,8 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
} else if (VD->getInit() && !isVarOnPath(Path, VD)) {
Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD});
visitLocalsRetainedByReferenceBinding(Path, VD->getInit(),
- RK_ReferenceBinding, Visit);
+ RK_ReferenceBinding, Visit,
+ EnableLifetimeWarnings);
}
}
break;
@@ -6702,13 +6986,15 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
// handling all sorts of rvalues passed to a unary operator.
const UnaryOperator *U = cast<UnaryOperator>(Init);
if (U->getOpcode() == UO_Deref)
- visitLocalsRetainedByInitializer(Path, U->getSubExpr(), Visit, true);
+ visitLocalsRetainedByInitializer(Path, U->getSubExpr(), Visit, true,
+ EnableLifetimeWarnings);
break;
}
case Stmt::OMPArraySectionExprClass: {
- visitLocalsRetainedByInitializer(
- Path, cast<OMPArraySectionExpr>(Init)->getBase(), Visit, true);
+ visitLocalsRetainedByInitializer(Path,
+ cast<OMPArraySectionExpr>(Init)->getBase(),
+ Visit, true, EnableLifetimeWarnings);
break;
}
@@ -6716,9 +7002,11 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
case Stmt::BinaryConditionalOperatorClass: {
auto *C = cast<AbstractConditionalOperator>(Init);
if (!C->getTrueExpr()->getType()->isVoidType())
- visitLocalsRetainedByReferenceBinding(Path, C->getTrueExpr(), RK, Visit);
+ visitLocalsRetainedByReferenceBinding(Path, C->getTrueExpr(), RK, Visit,
+ EnableLifetimeWarnings);
if (!C->getFalseExpr()->getType()->isVoidType())
- visitLocalsRetainedByReferenceBinding(Path, C->getFalseExpr(), RK, Visit);
+ visitLocalsRetainedByReferenceBinding(Path, C->getFalseExpr(), RK, Visit,
+ EnableLifetimeWarnings);
break;
}
@@ -6733,7 +7021,8 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
/// the prvalue expression \c Init.
static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
Expr *Init, LocalVisitor Visit,
- bool RevisitSubinits) {
+ bool RevisitSubinits,
+ bool EnableLifetimeWarnings) {
RevertToOldSizeRAII RAII(Path);
Expr *Old;
@@ -6773,15 +7062,17 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
if (VD && VD->getType().isConstQualified() && VD->getInit() &&
!isVarOnPath(Path, VD)) {
Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD});
- visitLocalsRetainedByInitializer(Path, VD->getInit(), Visit, true);
+ visitLocalsRetainedByInitializer(Path, VD->getInit(), Visit, true,
+ EnableLifetimeWarnings);
}
} else if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L)) {
if (MTE->getType().isConstQualified())
visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(),
- Visit, true);
+ Visit, true,
+ EnableLifetimeWarnings);
}
return false;
- });
+ }, EnableLifetimeWarnings);
// We assume that objects can be retained by pointers cast to integers,
// but not if the integer is cast to floating-point type or to _Complex.
@@ -6811,7 +7102,8 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
// lvalue.
Path.push_back({IndirectLocalPathEntry::AddressOf, CE});
return visitLocalsRetainedByReferenceBinding(Path, CE->getSubExpr(),
- RK_ReferenceBinding, Visit);
+ RK_ReferenceBinding, Visit,
+ EnableLifetimeWarnings);
default:
return;
@@ -6826,7 +7118,8 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
// lifetime of the array exactly like binding a reference to a temporary.
if (auto *ILE = dyn_cast<CXXStdInitializerListExpr>(Init))
return visitLocalsRetainedByReferenceBinding(Path, ILE->getSubExpr(),
- RK_StdInitializerList, Visit);
+ RK_StdInitializerList, Visit,
+ EnableLifetimeWarnings);
if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
// We already visited the elements of this initializer list while
@@ -6837,12 +7130,14 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
if (ILE->isTransparent())
return visitLocalsRetainedByInitializer(Path, ILE->getInit(0), Visit,
- RevisitSubinits);
+ RevisitSubinits,
+ EnableLifetimeWarnings);
if (ILE->getType()->isArrayType()) {
for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I)
visitLocalsRetainedByInitializer(Path, ILE->getInit(I), Visit,
- RevisitSubinits);
+ RevisitSubinits,
+ EnableLifetimeWarnings);
return;
}
@@ -6855,12 +7150,14 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
if (RD->isUnion() && ILE->getInitializedFieldInUnion() &&
ILE->getInitializedFieldInUnion()->getType()->isReferenceType())
visitLocalsRetainedByReferenceBinding(Path, ILE->getInit(0),
- RK_ReferenceBinding, Visit);
+ RK_ReferenceBinding, Visit,
+ EnableLifetimeWarnings);
else {
unsigned Index = 0;
for (; Index < RD->getNumBases() && Index < ILE->getNumInits(); ++Index)
visitLocalsRetainedByInitializer(Path, ILE->getInit(Index), Visit,
- RevisitSubinits);
+ RevisitSubinits,
+ EnableLifetimeWarnings);
for (const auto *I : RD->fields()) {
if (Index >= ILE->getNumInits())
break;
@@ -6869,13 +7166,15 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
Expr *SubInit = ILE->getInit(Index);
if (I->getType()->isReferenceType())
visitLocalsRetainedByReferenceBinding(Path, SubInit,
- RK_ReferenceBinding, Visit);
+ RK_ReferenceBinding, Visit,
+ EnableLifetimeWarnings);
else
// This might be either aggregate-initialization of a member or
// initialization of a std::initializer_list object. Regardless,
// we should recursively lifetime-extend that initializer.
visitLocalsRetainedByInitializer(Path, SubInit, Visit,
- RevisitSubinits);
+ RevisitSubinits,
+ EnableLifetimeWarnings);
++Index;
}
}
@@ -6891,14 +7190,18 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
continue;
if (E->isGLValue())
visitLocalsRetainedByReferenceBinding(Path, E, RK_ReferenceBinding,
- Visit);
+ Visit, EnableLifetimeWarnings);
else
- visitLocalsRetainedByInitializer(Path, E, Visit, true);
+ visitLocalsRetainedByInitializer(Path, E, Visit, true,
+ EnableLifetimeWarnings);
}
}
- if (isa<CallExpr>(Init) || isa<CXXConstructExpr>(Init))
+ if (isa<CallExpr>(Init) || isa<CXXConstructExpr>(Init)) {
+ if (EnableLifetimeWarnings)
+ handleGslAnnotatedTypes(Path, Init, Visit);
return visitLifetimeBoundArguments(Path, Init, Visit);
+ }
switch (Init->getStmtClass()) {
case Stmt::UnaryOperatorClass: {
@@ -6914,7 +7217,8 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
Path.push_back({IndirectLocalPathEntry::AddressOf, UO});
visitLocalsRetainedByReferenceBinding(Path, UO->getSubExpr(),
- RK_ReferenceBinding, Visit);
+ RK_ReferenceBinding, Visit,
+ EnableLifetimeWarnings);
}
break;
}
@@ -6927,9 +7231,11 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
break;
if (BO->getLHS()->getType()->isPointerType())
- visitLocalsRetainedByInitializer(Path, BO->getLHS(), Visit, true);
+ visitLocalsRetainedByInitializer(Path, BO->getLHS(), Visit, true,
+ EnableLifetimeWarnings);
else if (BO->getRHS()->getType()->isPointerType())
- visitLocalsRetainedByInitializer(Path, BO->getRHS(), Visit, true);
+ visitLocalsRetainedByInitializer(Path, BO->getRHS(), Visit, true,
+ EnableLifetimeWarnings);
break;
}
@@ -6939,9 +7245,11 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
// In C++, we can have a throw-expression operand, which has 'void' type
// and isn't interesting from a lifetime perspective.
if (!C->getTrueExpr()->getType()->isVoidType())
- visitLocalsRetainedByInitializer(Path, C->getTrueExpr(), Visit, true);
+ visitLocalsRetainedByInitializer(Path, C->getTrueExpr(), Visit, true,
+ EnableLifetimeWarnings);
if (!C->getFalseExpr()->getType()->isVoidType())
- visitLocalsRetainedByInitializer(Path, C->getFalseExpr(), Visit, true);
+ visitLocalsRetainedByInitializer(Path, C->getFalseExpr(), Visit, true,
+ EnableLifetimeWarnings);
break;
}
@@ -6980,18 +7288,33 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
case IndirectLocalPathEntry::AddressOf:
case IndirectLocalPathEntry::LValToRVal:
case IndirectLocalPathEntry::LifetimeBoundCall:
+ case IndirectLocalPathEntry::GslPointerInit:
// These exist primarily to mark the path as not permitting or
// supporting lifetime extension.
break;
- case IndirectLocalPathEntry::DefaultInit:
case IndirectLocalPathEntry::VarInit:
+ if (cast<VarDecl>(Path[I].D)->isImplicit())
+ return SourceRange();
+ LLVM_FALLTHROUGH;
+ case IndirectLocalPathEntry::DefaultInit:
return Path[I].E->getSourceRange();
}
}
return E->getSourceRange();
}
+static bool pathOnlyInitializesGslPointer(IndirectLocalPath &Path) {
+ for (auto It = Path.rbegin(), End = Path.rend(); It != End; ++It) {
+ if (It->Kind == IndirectLocalPathEntry::VarInit)
+ continue;
+ if (It->Kind == IndirectLocalPathEntry::AddressOf)
+ continue;
+ return It->Kind == IndirectLocalPathEntry::GslPointerInit;
+ }
+ return false;
+}
+
void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
Expr *Init) {
LifetimeResult LR = getEntityLifetime(&Entity);
@@ -7008,12 +7331,36 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
SourceRange DiagRange = nextPathEntryRange(Path, 0, L);
SourceLocation DiagLoc = DiagRange.getBegin();
+ auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L);
+
+ bool IsGslPtrInitWithGslTempOwner = false;
+ bool IsLocalGslOwner = false;
+ if (pathOnlyInitializesGslPointer(Path)) {
+ if (isa<DeclRefExpr>(L)) {
+ // We do not want to follow the references when returning a pointer originating
+ // from a local owner to avoid the following false positive:
+ // int &p = *localUniquePtr;
+ // someContainer.add(std::move(localUniquePtr));
+ // return p;
+ IsLocalGslOwner = isRecordWithAttr<OwnerAttr>(L->getType());
+ if (pathContainsInit(Path) || !IsLocalGslOwner)
+ return false;
+ } else {
+ IsGslPtrInitWithGslTempOwner = MTE && !MTE->getExtendingDecl() &&
+ isRecordWithAttr<OwnerAttr>(MTE->getType());
+ // Skipping a chain of initializing gsl::Pointer annotated objects.
+ // We are looking only for the final source to find out if it was
+ // a local or temporary owner or the address of a local variable/param.
+ if (!IsGslPtrInitWithGslTempOwner)
+ return true;
+ }
+ }
+
switch (LK) {
case LK_FullExpression:
llvm_unreachable("already handled this");
case LK_Extended: {
- auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L);
if (!MTE) {
// The initialized entity has lifetime beyond the full-expression,
// and the local entity does too, so don't warn.
@@ -7023,6 +7370,11 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
return false;
}
+ if (IsGslPtrInitWithGslTempOwner && DiagLoc.isValid()) {
+ Diag(DiagLoc, diag::warn_dangling_lifetime_pointer) << DiagRange;
+ return false;
+ }
+
// Lifetime-extend the temporary.
if (Path.empty()) {
// Update the storage duration of the materialized temporary.
@@ -7064,6 +7416,14 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
// temporary, the program is ill-formed.
if (auto *ExtendingDecl =
ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) {
+ if (IsGslPtrInitWithGslTempOwner) {
+ Diag(DiagLoc, diag::warn_dangling_lifetime_pointer_member)
+ << ExtendingDecl << DiagRange;
+ Diag(ExtendingDecl->getLocation(),
+ diag::note_ref_or_ptr_member_declared_here)
+ << true;
+ return false;
+ }
bool IsSubobjectMember = ExtendingEntity != &Entity;
Diag(DiagLoc, shouldLifetimeExtendThroughPath(Path)
? diag::err_dangling_member
@@ -7094,6 +7454,11 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
if (pathContainsInit(Path))
return false;
+ // Suppress false positives for code like the one below:
+ // Ctor(unique_ptr<T> up) : member(*up), member2(move(up)) {}
+ if (IsLocalGslOwner && pathOnlyInitializesGslPointer(Path))
+ return false;
+
auto *DRE = dyn_cast<DeclRefExpr>(L);
auto *VD = DRE ? dyn_cast<VarDecl>(DRE->getDecl()) : nullptr;
if (!VD) {
@@ -7104,7 +7469,7 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
if (auto *Member =
ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) {
- bool IsPointer = Member->getType()->isAnyPointerType();
+ bool IsPointer = !Member->getType()->isReferenceType();
Diag(DiagLoc, IsPointer ? diag::warn_init_ptr_member_to_parameter_addr
: diag::warn_bind_ref_member_to_parameter)
<< Member << VD << isa<ParmVarDecl>(VD) << DiagRange;
@@ -7118,10 +7483,13 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
case LK_New:
if (isa<MaterializeTemporaryExpr>(L)) {
- Diag(DiagLoc, RK == RK_ReferenceBinding
- ? diag::warn_new_dangling_reference
- : diag::warn_new_dangling_initializer_list)
- << !Entity.getParent() << DiagRange;
+ if (IsGslPtrInitWithGslTempOwner)
+ Diag(DiagLoc, diag::warn_dangling_lifetime_pointer) << DiagRange;
+ else
+ Diag(DiagLoc, RK == RK_ReferenceBinding
+ ? diag::warn_new_dangling_reference
+ : diag::warn_new_dangling_initializer_list)
+ << !Entity.getParent() << DiagRange;
} else {
// We can't determine if the allocation outlives the local declaration.
return false;
@@ -7164,7 +7532,8 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
break;
case IndirectLocalPathEntry::LifetimeBoundCall:
- // FIXME: Consider adding a note for this.
+ case IndirectLocalPathEntry::GslPointerInit:
+ // FIXME: Consider adding a note for these.
break;
case IndirectLocalPathEntry::DefaultInit: {
@@ -7189,12 +7558,16 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
return false;
};
+ bool EnableLifetimeWarnings = !getDiagnostics().isIgnored(
+ diag::warn_dangling_lifetime_pointer, SourceLocation());
llvm::SmallVector<IndirectLocalPathEntry, 8> Path;
if (Init->isGLValue())
visitLocalsRetainedByReferenceBinding(Path, Init, RK_ReferenceBinding,
- TemporaryVisitor);
+ TemporaryVisitor,
+ EnableLifetimeWarnings);
else
- visitLocalsRetainedByInitializer(Path, Init, TemporaryVisitor, false);
+ visitLocalsRetainedByInitializer(Path, Init, TemporaryVisitor, false,
+ EnableLifetimeWarnings);
}
static void DiagnoseNarrowingInInitList(Sema &S,
@@ -7837,7 +8210,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
Ty = S.Context.getRValueReferenceType(Ty);
else if ((*ResultType)->isLValueReferenceType())
Ty = S.Context.getLValueReferenceType(Ty,
- (*ResultType)->getAs<LValueReferenceType>()->isSpelledAsLValue());
+ (*ResultType)->castAs<LValueReferenceType>()->isSpelledAsLValue());
*ResultType = Ty;
}
@@ -8043,6 +8416,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
*ResultType = S.Context.getConstantArrayType(
IncompleteDest->getElementType(),
ConstantSource->getSize(),
+ ConstantSource->getSizeExpr(),
ArrayType::Normal, 0);
}
}
@@ -8108,7 +8482,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
// argument passing.
assert(Step->Type->isSamplerT() &&
"Sampler initialization on non-sampler type.");
- Expr *Init = CurInit.get();
+ Expr *Init = CurInit.get()->IgnoreParens();
QualType SourceType = Init->getType();
// Case 1
if (Entity.isParameterKind()) {
@@ -8285,7 +8659,7 @@ static void diagnoseListInit(Sema &S, const InitializedEntity &Entity,
E.withConst(),
llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
InitList->getNumInits()),
- clang::ArrayType::Normal, 0);
+ nullptr, clang::ArrayType::Normal, 0);
InitializedEntity HiddenArray =
InitializedEntity::InitializeTemporary(ArrayType);
return diagnoseListInit(S, HiddenArray, InitList);
@@ -8295,7 +8669,7 @@ static void diagnoseListInit(Sema &S, const InitializedEntity &Entity,
// A list-initialization failure for a reference means that we tried to
// create a temporary of the inner type (per [dcl.init.list]p3.6) and the
// inner initialization failed.
- QualType T = DestType->getAs<ReferenceType>()->getPointeeType();
+ QualType T = DestType->castAs<ReferenceType>()->getPointeeType();
diagnoseListInit(S, InitializedEntity::InitializeTemporary(T), InitList);
SourceLocation Loc = InitList->getBeginLoc();
if (auto *D = Entity.getDecl())
@@ -8652,7 +9026,7 @@ bool InitializationSequence::Diagnose(Sema &S,
<< InheritedFrom;
RecordDecl *BaseDecl
- = Entity.getBaseSpecifier()->getType()->getAs<RecordType>()
+ = Entity.getBaseSpecifier()->getType()->castAs<RecordType>()
->getDecl();
S.Diag(BaseDecl->getLocation(), diag::note_previous_decl)
<< S.Context.getTagDeclType(BaseDecl);
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 986524e6d56b..c6b19a0b195c 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -272,12 +272,11 @@ static bool isInInlineFunction(const DeclContext *DC) {
return false;
}
-MangleNumberingContext *
-Sema::getCurrentMangleNumberContext(const DeclContext *DC,
- Decl *&ManglingContextDecl) {
+std::tuple<MangleNumberingContext *, Decl *>
+Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
// Compute the context for allocating mangling numbers in the current
// expression, if the ABI requires them.
- ManglingContextDecl = ExprEvalContexts.back().ManglingContextDecl;
+ Decl *ManglingContextDecl = ExprEvalContexts.back().ManglingContextDecl;
enum ContextKind {
Normal,
@@ -325,22 +324,18 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC,
if ((IsInNonspecializedTemplate &&
!(ManglingContextDecl && isa<ParmVarDecl>(ManglingContextDecl))) ||
isInInlineFunction(CurContext)) {
- ManglingContextDecl = nullptr;
while (auto *CD = dyn_cast<CapturedDecl>(DC))
DC = CD->getParent();
- return &Context.getManglingNumberContext(DC);
+ return std::make_tuple(&Context.getManglingNumberContext(DC), nullptr);
}
- ManglingContextDecl = nullptr;
- return nullptr;
+ return std::make_tuple(nullptr, nullptr);
}
case StaticDataMember:
// -- the initializers of nonspecialized static members of template classes
- if (!IsInNonspecializedTemplate) {
- ManglingContextDecl = nullptr;
- return nullptr;
- }
+ if (!IsInNonspecializedTemplate)
+ return std::make_tuple(nullptr, ManglingContextDecl);
// Fall through to get the current context.
LLVM_FALLTHROUGH;
@@ -352,29 +347,24 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC,
// -- the initializers of inline variables
case VariableTemplate:
// -- the initializers of templated variables
- return &ExprEvalContexts.back().getMangleNumberingContext(Context);
+ return std::make_tuple(
+ &Context.getManglingNumberContext(ASTContext::NeedExtraManglingDecl,
+ ManglingContextDecl),
+ ManglingContextDecl);
}
llvm_unreachable("unexpected context");
}
-MangleNumberingContext &
-Sema::ExpressionEvaluationContextRecord::getMangleNumberingContext(
- ASTContext &Ctx) {
- assert(ManglingContextDecl && "Need to have a context declaration");
- if (!MangleNumbering)
- MangleNumbering = Ctx.createMangleNumberingContext();
- return *MangleNumbering;
-}
-
-CXXMethodDecl *Sema::startLambdaDefinition(
- CXXRecordDecl *Class, SourceRange IntroducerRange,
- TypeSourceInfo *MethodTypeInfo, SourceLocation EndLoc,
- ArrayRef<ParmVarDecl *> Params, ConstexprSpecKind ConstexprKind,
- Optional<std::pair<unsigned, Decl *>> Mangling) {
+CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
+ SourceRange IntroducerRange,
+ TypeSourceInfo *MethodTypeInfo,
+ SourceLocation EndLoc,
+ ArrayRef<ParmVarDecl *> Params,
+ ConstexprSpecKind ConstexprKind) {
QualType MethodType = MethodTypeInfo->getType();
TemplateParameterList *TemplateParams =
- getGenericLambdaTemplateParameterList(getCurLambda(), *this);
+ getGenericLambdaTemplateParameterList(getCurLambda(), *this);
// If a lambda appears in a dependent context or is a generic lambda (has
// template parameters) and has an 'auto' return type, deduce it to a
// dependent type.
@@ -407,6 +397,8 @@ CXXMethodDecl *Sema::startLambdaDefinition(
MethodType, MethodTypeInfo, SC_None,
/*isInline=*/true, ConstexprKind, EndLoc);
Method->setAccess(AS_public);
+ if (!TemplateParams)
+ Class->addDecl(Method);
// Temporarily set the lexical declaration context to the current
// context, so that the Scope stack matches the lexical nesting.
@@ -418,9 +410,10 @@ CXXMethodDecl *Sema::startLambdaDefinition(
TemplateParams,
Method) : nullptr;
if (TemplateMethod) {
- TemplateMethod->setLexicalDeclContext(CurContext);
TemplateMethod->setAccess(AS_public);
Method->setDescribedFunctionTemplate(TemplateMethod);
+ Class->addDecl(TemplateMethod);
+ TemplateMethod->setLexicalDeclContext(CurContext);
}
// Add parameters.
@@ -433,19 +426,56 @@ CXXMethodDecl *Sema::startLambdaDefinition(
P->setOwningFunction(Method);
}
+ return Method;
+}
+
+void Sema::handleLambdaNumbering(
+ CXXRecordDecl *Class, CXXMethodDecl *Method,
+ Optional<std::tuple<unsigned, bool, Decl *>> Mangling) {
if (Mangling) {
- Class->setLambdaMangling(Mangling->first, Mangling->second);
- } else {
+ unsigned ManglingNumber;
+ bool HasKnownInternalLinkage;
Decl *ManglingContextDecl;
- if (MangleNumberingContext *MCtx =
- getCurrentMangleNumberContext(Class->getDeclContext(),
- ManglingContextDecl)) {
- unsigned ManglingNumber = MCtx->getManglingNumber(Method);
- Class->setLambdaMangling(ManglingNumber, ManglingContextDecl);
- }
+ std::tie(ManglingNumber, HasKnownInternalLinkage, ManglingContextDecl) =
+ Mangling.getValue();
+ Class->setLambdaMangling(ManglingNumber, ManglingContextDecl,
+ HasKnownInternalLinkage);
+ return;
}
- return Method;
+ auto getMangleNumberingContext =
+ [this](CXXRecordDecl *Class,
+ Decl *ManglingContextDecl) -> MangleNumberingContext * {
+ // Get mangle numbering context if there's any extra decl context.
+ if (ManglingContextDecl)
+ return &Context.getManglingNumberContext(
+ ASTContext::NeedExtraManglingDecl, ManglingContextDecl);
+ // Otherwise, from that lambda's decl context.
+ auto DC = Class->getDeclContext();
+ while (auto *CD = dyn_cast<CapturedDecl>(DC))
+ DC = CD->getParent();
+ return &Context.getManglingNumberContext(DC);
+ };
+
+ MangleNumberingContext *MCtx;
+ Decl *ManglingContextDecl;
+ std::tie(MCtx, ManglingContextDecl) =
+ getCurrentMangleNumberContext(Class->getDeclContext());
+ bool HasKnownInternalLinkage = false;
+ if (!MCtx && getLangOpts().CUDA) {
+ // Force lambda numbering in CUDA/HIP as we need to name lambdas following
+ // ODR. Both device- and host-compilation need to have a consistent naming
+ // on kernel functions. As lambdas are potential part of these `__global__`
+ // function names, they needs numbering following ODR.
+ MCtx = getMangleNumberingContext(Class, ManglingContextDecl);
+ assert(MCtx && "Retrieving mangle numbering context failed!");
+ HasKnownInternalLinkage = true;
+ }
+ if (MCtx) {
+ unsigned ManglingNumber = MCtx->getManglingNumber(Method);
+ Class->setLambdaMangling(ManglingNumber, ManglingContextDecl,
+ HasKnownInternalLinkage);
+ }
}
void Sema::buildLambdaScope(LambdaScopeInfo *LSI,
@@ -839,6 +869,8 @@ VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
NewVD->setInitStyle(static_cast<VarDecl::InitializationStyle>(InitStyle));
NewVD->markUsed(Context);
NewVD->setInit(Init);
+ if (NewVD->isParameterPack())
+ getCurLambda()->LocalPacks.push_back(NewVD);
return NewVD;
}
@@ -928,12 +960,12 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// Check for unexpanded parameter packs in the method type.
if (MethodTyInfo->getType()->containsUnexpandedParameterPack())
- ContainsUnexpandedParameterPack = true;
+ DiagnoseUnexpandedParameterPack(Intro.Range.getBegin(), MethodTyInfo,
+ UPPC_DeclarationType);
}
CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, MethodTyInfo,
KnownDependent, Intro.Default);
-
CXXMethodDecl *Method =
startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
ParamInfo.getDeclSpec().getConstexprSpecifier());
@@ -956,6 +988,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (getLangOpts().CUDA)
CUDASetLambdaAttrs(Method);
+ // Number the lambda for linkage purposes if necessary.
+ handleLambdaNumbering(Class, Method);
+
// Introduce the function call operator as the current declaration context.
PushDeclContext(CurScope, Method);
@@ -1053,7 +1088,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (C->Init.get()->containsUnexpandedParameterPack() &&
!C->InitCaptureType.get()->getAs<PackExpansionType>())
- ContainsUnexpandedParameterPack = true;
+ DiagnoseUnexpandedParameterPack(C->Init.get(), UPPC_Initializer);
unsigned InitStyle;
switch (C->InitKind) {
@@ -1184,7 +1219,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
}
finishLambdaExplicitCaptures(LSI);
- LSI->ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
+ LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack;
// Add lambda parameters into scope.
addLambdaParameters(Intro.Captures, Method, CurScope);
@@ -1639,8 +1674,9 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
? CallOperator->getDescribedFunctionTemplate()
: cast<Decl>(CallOperator);
+ // FIXME: Is this really the best choice? Keeping the lexical decl context
+ // set as CurContext seems more faithful to the source.
TemplateOrNonTemplateCallOperatorDecl->setLexicalDeclContext(Class);
- Class->addDecl(TemplateOrNonTemplateCallOperatorDecl);
PopExpressionEvaluationContext();
@@ -1776,10 +1812,9 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
!CallOperator->isConstexpr() &&
!isa<CoroutineBodyStmt>(CallOperator->getBody()) &&
!Class->getDeclContext()->isDependentContext()) {
- TentativeAnalysisScope DiagnosticScopeGuard(*this);
CallOperator->setConstexprKind(
- (CheckConstexprFunctionDecl(CallOperator) &&
- CheckConstexprFunctionBody(CallOperator, CallOperator->getBody()))
+ CheckConstexprFunctionDefinition(CallOperator,
+ CheckConstexprKind::CheckValid)
? CSK_constexpr
: CSK_unspecified);
}
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 8a24dd884a76..d56c5980237c 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -673,82 +673,160 @@ LLVM_DUMP_METHOD void LookupResult::dump() {
D->dump();
}
-/// When trying to resolve a function name, if the isOpenCLBuiltin function
-/// defined in "OpenCLBuiltins.inc" returns a non-null <Index, Len>, then the
-/// identifier is referencing an OpenCL builtin function. Thus, all its
-/// prototypes are added to the LookUpResult.
+/// Get the QualType instances of the return type and arguments for an OpenCL
+/// builtin function signature.
+/// \param Context (in) The Context instance.
+/// \param OpenCLBuiltin (in) The signature currently handled.
+/// \param GenTypeMaxCnt (out) Maximum number of types contained in a generic
+/// type used as return type or as argument.
+/// Only meaningful for generic types, otherwise equals 1.
+/// \param RetTypes (out) List of the possible return types.
+/// \param ArgTypes (out) List of the possible argument types. For each
+/// argument, ArgTypes contains QualTypes for the Cartesian product
+/// of (vector sizes) x (types) .
+static void GetQualTypesForOpenCLBuiltin(
+ ASTContext &Context, const OpenCLBuiltinStruct &OpenCLBuiltin,
+ unsigned &GenTypeMaxCnt, SmallVector<QualType, 1> &RetTypes,
+ SmallVector<SmallVector<QualType, 1>, 5> &ArgTypes) {
+ // Get the QualType instances of the return types.
+ unsigned Sig = SignatureTable[OpenCLBuiltin.SigTableIndex];
+ OCL2Qual(Context, TypeTable[Sig], RetTypes);
+ GenTypeMaxCnt = RetTypes.size();
+
+ // Get the QualType instances of the arguments.
+ // First type is the return type, skip it.
+ for (unsigned Index = 1; Index < OpenCLBuiltin.NumTypes; Index++) {
+ SmallVector<QualType, 1> Ty;
+ OCL2Qual(Context,
+ TypeTable[SignatureTable[OpenCLBuiltin.SigTableIndex + Index]], Ty);
+ GenTypeMaxCnt = (Ty.size() > GenTypeMaxCnt) ? Ty.size() : GenTypeMaxCnt;
+ ArgTypes.push_back(std::move(Ty));
+ }
+}
+
+/// Create a list of the candidate function overloads for an OpenCL builtin
+/// function.
+/// \param Context (in) The ASTContext instance.
+/// \param GenTypeMaxCnt (in) Maximum number of types contained in a generic
+/// type used as return type or as argument.
+/// Only meaningful for generic types, otherwise equals 1.
+/// \param FunctionList (out) List of FunctionTypes.
+/// \param RetTypes (in) List of the possible return types.
+/// \param ArgTypes (in) List of the possible types for the arguments.
+static void GetOpenCLBuiltinFctOverloads(
+ ASTContext &Context, unsigned GenTypeMaxCnt,
+ std::vector<QualType> &FunctionList, SmallVector<QualType, 1> &RetTypes,
+ SmallVector<SmallVector<QualType, 1>, 5> &ArgTypes) {
+ FunctionProtoType::ExtProtoInfo PI;
+ PI.Variadic = false;
+
+ // Create FunctionTypes for each (gen)type.
+ for (unsigned IGenType = 0; IGenType < GenTypeMaxCnt; IGenType++) {
+ SmallVector<QualType, 5> ArgList;
+
+ for (unsigned A = 0; A < ArgTypes.size(); A++) {
+ // Builtins such as "max" have an "sgentype" argument that represents
+ // the corresponding scalar type of a gentype. The number of gentypes
+ // must be a multiple of the number of sgentypes.
+ assert(GenTypeMaxCnt % ArgTypes[A].size() == 0 &&
+ "argument type count not compatible with gentype type count");
+ unsigned Idx = IGenType % ArgTypes[A].size();
+ ArgList.push_back(ArgTypes[A][Idx]);
+ }
+
+ FunctionList.push_back(Context.getFunctionType(
+ RetTypes[(RetTypes.size() != 1) ? IGenType : 0], ArgList, PI));
+ }
+}
+
+/// When trying to resolve a function name, if isOpenCLBuiltin() returns a
+/// non-null <Index, Len> pair, then the name is referencing an OpenCL
+/// builtin function. Add all candidate signatures to the LookUpResult.
///
-/// \param S The Sema instance
-/// \param LR The LookupResult instance
-/// \param II The identifier being resolved
-/// \param Index The list of prototypes starts at Index in OpenCLBuiltins[]
-/// \param Len The list of prototypes has Len elements
-static void InsertOCLBuiltinDeclarations(Sema &S, LookupResult &LR,
- IdentifierInfo *II, unsigned Index,
- unsigned Len) {
-
- for (unsigned i = 0; i < Len; ++i) {
- const OpenCLBuiltinDecl &Decl = OpenCLBuiltins[Index - 1 + i];
+/// \param S (in) The Sema instance.
+/// \param LR (inout) The LookupResult instance.
+/// \param II (in) The identifier being resolved.
+/// \param FctIndex (in) Starting index in the BuiltinTable.
+/// \param Len (in) The signature list has Len elements.
+static void InsertOCLBuiltinDeclarationsFromTable(Sema &S, LookupResult &LR,
+ IdentifierInfo *II,
+ const unsigned FctIndex,
+ const unsigned Len) {
+ // The builtin function declaration uses generic types (gentype).
+ bool HasGenType = false;
+
+ // Maximum number of types contained in a generic type used as return type or
+ // as argument. Only meaningful for generic types, otherwise equals 1.
+ unsigned GenTypeMaxCnt;
+
+ for (unsigned SignatureIndex = 0; SignatureIndex < Len; SignatureIndex++) {
+ const OpenCLBuiltinStruct &OpenCLBuiltin =
+ BuiltinTable[FctIndex + SignatureIndex];
ASTContext &Context = S.Context;
- // Ignore this BIF if the version is incorrect.
- if (Context.getLangOpts().OpenCLVersion < Decl.Version)
+ // Ignore this BIF if its version does not match the language options.
+ if (Context.getLangOpts().OpenCLVersion < OpenCLBuiltin.MinVersion)
+ continue;
+ if ((OpenCLBuiltin.MaxVersion != 0) &&
+ (Context.getLangOpts().OpenCLVersion >= OpenCLBuiltin.MaxVersion))
continue;
- FunctionProtoType::ExtProtoInfo PI;
- PI.Variadic = false;
-
- // Defined in "OpenCLBuiltins.inc"
- QualType RT = OCL2Qual(Context, OpenCLSignature[Decl.ArgTableIndex]);
+ SmallVector<QualType, 1> RetTypes;
+ SmallVector<SmallVector<QualType, 1>, 5> ArgTypes;
- SmallVector<QualType, 5> ArgTypes;
- for (unsigned I = 1; I < Decl.NumArgs; I++) {
- QualType Ty = OCL2Qual(Context, OpenCLSignature[Decl.ArgTableIndex + I]);
- ArgTypes.push_back(Ty);
+ // Obtain QualType lists for the function signature.
+ GetQualTypesForOpenCLBuiltin(Context, OpenCLBuiltin, GenTypeMaxCnt,
+ RetTypes, ArgTypes);
+ if (GenTypeMaxCnt > 1) {
+ HasGenType = true;
}
- QualType R = Context.getFunctionType(RT, ArgTypes, PI);
- SourceLocation Loc = LR.getNameLoc();
+ // Create function overload for each type combination.
+ std::vector<QualType> FunctionList;
+ GetOpenCLBuiltinFctOverloads(Context, GenTypeMaxCnt, FunctionList, RetTypes,
+ ArgTypes);
- // TODO: This part is taken from Sema::LazilyCreateBuiltin,
- // maybe refactor it.
+ SourceLocation Loc = LR.getNameLoc();
DeclContext *Parent = Context.getTranslationUnitDecl();
- FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, R,
- /*TInfo=*/nullptr, SC_Extern,
- false, R->isFunctionProtoType());
- New->setImplicit();
-
- // Create Decl objects for each parameter, adding them to the
- // FunctionDecl.
- if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) {
- SmallVector<ParmVarDecl *, 16> Params;
- for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) {
- ParmVarDecl *Parm =
- ParmVarDecl::Create(Context, New, SourceLocation(),
- SourceLocation(), nullptr, FT->getParamType(i),
- /*TInfo=*/nullptr, SC_None, nullptr);
- Parm->setScopeInfo(0, i);
- Params.push_back(Parm);
+ FunctionDecl *NewOpenCLBuiltin;
+
+ for (unsigned Index = 0; Index < GenTypeMaxCnt; Index++) {
+ NewOpenCLBuiltin = FunctionDecl::Create(
+ Context, Parent, Loc, Loc, II, FunctionList[Index],
+ /*TInfo=*/nullptr, SC_Extern, false,
+ FunctionList[Index]->isFunctionProtoType());
+ NewOpenCLBuiltin->setImplicit();
+
+ // Create Decl objects for each parameter, adding them to the
+ // FunctionDecl.
+ if (const FunctionProtoType *FP =
+ dyn_cast<FunctionProtoType>(FunctionList[Index])) {
+ SmallVector<ParmVarDecl *, 16> ParmList;
+ for (unsigned IParm = 0, e = FP->getNumParams(); IParm != e; ++IParm) {
+ ParmVarDecl *Parm = ParmVarDecl::Create(
+ Context, NewOpenCLBuiltin, SourceLocation(), SourceLocation(),
+ nullptr, FP->getParamType(IParm),
+ /*TInfo=*/nullptr, SC_None, nullptr);
+ Parm->setScopeInfo(0, IParm);
+ ParmList.push_back(Parm);
+ }
+ NewOpenCLBuiltin->setParams(ParmList);
}
- New->setParams(Params);
+ if (!S.getLangOpts().OpenCLCPlusPlus) {
+ NewOpenCLBuiltin->addAttr(OverloadableAttr::CreateImplicit(Context));
+ }
+ LR.addDecl(NewOpenCLBuiltin);
}
-
- New->addAttr(OverloadableAttr::CreateImplicit(Context));
-
- if (strlen(Decl.Extension))
- S.setOpenCLExtensionForDecl(New, Decl.Extension);
-
- LR.addDecl(New);
}
// If we added overloads, need to resolve the lookup result.
- if (Len > 1)
+ if (Len > 1 || HasGenType)
LR.resolveKind();
}
/// Lookup a builtin function, when name lookup would otherwise
/// fail.
-static bool LookupBuiltin(Sema &S, LookupResult &R) {
+bool Sema::LookupBuiltin(LookupResult &R) {
Sema::LookupNameKind NameKind = R.getLookupKind();
// If we didn't find a use of this identifier, and if the identifier
@@ -758,21 +836,22 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
NameKind == Sema::LookupRedeclarationWithLinkage) {
IdentifierInfo *II = R.getLookupName().getAsIdentifierInfo();
if (II) {
- if (S.getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName) {
- if (II == S.getASTContext().getMakeIntegerSeqName()) {
- R.addDecl(S.getASTContext().getMakeIntegerSeqDecl());
+ if (getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName) {
+ if (II == getASTContext().getMakeIntegerSeqName()) {
+ R.addDecl(getASTContext().getMakeIntegerSeqDecl());
return true;
- } else if (II == S.getASTContext().getTypePackElementName()) {
- R.addDecl(S.getASTContext().getTypePackElementDecl());
+ } else if (II == getASTContext().getTypePackElementName()) {
+ R.addDecl(getASTContext().getTypePackElementDecl());
return true;
}
}
// Check if this is an OpenCL Builtin, and if so, insert its overloads.
- if (S.getLangOpts().OpenCL && S.getLangOpts().DeclareOpenCLBuiltins) {
+ if (getLangOpts().OpenCL && getLangOpts().DeclareOpenCLBuiltins) {
auto Index = isOpenCLBuiltin(II->getName());
if (Index.first) {
- InsertOCLBuiltinDeclarations(S, R, II, Index.first, Index.second);
+ InsertOCLBuiltinDeclarationsFromTable(*this, R, II, Index.first - 1,
+ Index.second);
return true;
}
}
@@ -781,14 +860,14 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
if (unsigned BuiltinID = II->getBuiltinID()) {
// In C++ and OpenCL (spec v1.2 s6.9.f), we don't have any predefined
// library functions like 'malloc'. Instead, we'll just error.
- if ((S.getLangOpts().CPlusPlus || S.getLangOpts().OpenCL) &&
- S.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
+ if ((getLangOpts().CPlusPlus || getLangOpts().OpenCL) &&
+ Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
return false;
- if (NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II,
- BuiltinID, S.TUScope,
- R.isForRedeclaration(),
- R.getNameLoc())) {
+ if (NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II,
+ BuiltinID, TUScope,
+ R.isForRedeclaration(),
+ R.getNameLoc())) {
R.addDecl(D);
return true;
}
@@ -934,7 +1013,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
}
}
- if (!Found && DC->isTranslationUnit() && LookupBuiltin(S, R))
+ if (!Found && DC->isTranslationUnit() && S.LookupBuiltin(R))
return true;
if (R.getLookupName().getNameKind()
@@ -1932,7 +2011,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
// If we didn't find a use of this identifier, and if the identifier
// corresponds to a compiler builtin, create the decl object for the builtin
// now, injecting it into translation unit scope, and return it.
- if (AllowBuiltinCreation && LookupBuiltin(*this, R))
+ if (AllowBuiltinCreation && LookupBuiltin(R))
return true;
// If we didn't find a use of this identifier, the ExternalSource
@@ -2051,7 +2130,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
/// Callback that looks for any member of a class with the given name.
static bool LookupAnyMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path, DeclarationName Name) {
- RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
+ RecordDecl *BaseRecord = Specifier->getType()->castAs<RecordType>()->getDecl();
Path.Decls = BaseRecord->lookup(Name);
return !Path.Decls.empty();
@@ -2750,7 +2829,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
#define ABSTRACT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
// T is canonical. We can also ignore dependent types because
// we don't need to do ADL at the definition point, but if we
// wanted to implement template export (or if we find some other
@@ -3016,8 +3095,11 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
SpecialMemberCache.InsertNode(Result, InsertPoint);
if (SM == CXXDestructor) {
- if (RD->needsImplicitDestructor())
- DeclareImplicitDestructor(RD);
+ if (RD->needsImplicitDestructor()) {
+ runWithSufficientStackSpace(RD->getLocation(), [&] {
+ DeclareImplicitDestructor(RD);
+ });
+ }
CXXDestructorDecl *DD = RD->getDestructor();
assert(DD && "record without a destructor");
Result->setMethod(DD);
@@ -3040,21 +3122,36 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
if (SM == CXXDefaultConstructor) {
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
NumArgs = 0;
- if (RD->needsImplicitDefaultConstructor())
- DeclareImplicitDefaultConstructor(RD);
+ if (RD->needsImplicitDefaultConstructor()) {
+ runWithSufficientStackSpace(RD->getLocation(), [&] {
+ DeclareImplicitDefaultConstructor(RD);
+ });
+ }
} else {
if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) {
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
- if (RD->needsImplicitCopyConstructor())
- DeclareImplicitCopyConstructor(RD);
- if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveConstructor())
- DeclareImplicitMoveConstructor(RD);
+ if (RD->needsImplicitCopyConstructor()) {
+ runWithSufficientStackSpace(RD->getLocation(), [&] {
+ DeclareImplicitCopyConstructor(RD);
+ });
+ }
+ if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveConstructor()) {
+ runWithSufficientStackSpace(RD->getLocation(), [&] {
+ DeclareImplicitMoveConstructor(RD);
+ });
+ }
} else {
Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
- if (RD->needsImplicitCopyAssignment())
- DeclareImplicitCopyAssignment(RD);
- if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveAssignment())
- DeclareImplicitMoveAssignment(RD);
+ if (RD->needsImplicitCopyAssignment()) {
+ runWithSufficientStackSpace(RD->getLocation(), [&] {
+ DeclareImplicitCopyAssignment(RD);
+ });
+ }
+ if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveAssignment()) {
+ runWithSufficientStackSpace(RD->getLocation(), [&] {
+ DeclareImplicitMoveAssignment(RD);
+ });
+ }
}
if (ConstArg)
@@ -3211,12 +3308,14 @@ CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class,
DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
// If the implicit constructors have not yet been declared, do so now.
if (CanDeclareSpecialMemberFunction(Class)) {
- if (Class->needsImplicitDefaultConstructor())
- DeclareImplicitDefaultConstructor(Class);
- if (Class->needsImplicitCopyConstructor())
- DeclareImplicitCopyConstructor(Class);
- if (getLangOpts().CPlusPlus11 && Class->needsImplicitMoveConstructor())
- DeclareImplicitMoveConstructor(Class);
+ runWithSufficientStackSpace(Class->getLocation(), [&] {
+ if (Class->needsImplicitDefaultConstructor())
+ DeclareImplicitDefaultConstructor(Class);
+ if (Class->needsImplicitCopyConstructor())
+ DeclareImplicitCopyConstructor(Class);
+ if (getLangOpts().CPlusPlus11 && Class->needsImplicitMoveConstructor())
+ DeclareImplicitMoveConstructor(Class);
+ });
}
CanQualType T = Context.getCanonicalType(Context.getTypeDeclType(Class));
@@ -3609,328 +3708,347 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
return nullptr;
}
-static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
- bool QualifiedNameLookup,
- bool InBaseClass,
- VisibleDeclConsumer &Consumer,
- VisibleDeclsRecord &Visited,
- bool IncludeDependentBases,
- bool LoadExternal) {
- if (!Ctx)
- return;
-
- // Make sure we don't visit the same context twice.
- if (Visited.visitedContext(Ctx->getPrimaryContext()))
- return;
-
- Consumer.EnteredContext(Ctx);
-
- // Outside C++, lookup results for the TU live on identifiers.
- if (isa<TranslationUnitDecl>(Ctx) &&
- !Result.getSema().getLangOpts().CPlusPlus) {
- auto &S = Result.getSema();
- auto &Idents = S.Context.Idents;
-
- // Ensure all external identifiers are in the identifier table.
- if (LoadExternal)
- if (IdentifierInfoLookup *External = Idents.getExternalIdentifierLookup()) {
- std::unique_ptr<IdentifierIterator> Iter(External->getIdentifiers());
- for (StringRef Name = Iter->Next(); !Name.empty(); Name = Iter->Next())
- Idents.get(Name);
- }
+namespace {
+class LookupVisibleHelper {
+public:
+ LookupVisibleHelper(VisibleDeclConsumer &Consumer, bool IncludeDependentBases,
+ bool LoadExternal)
+ : Consumer(Consumer), IncludeDependentBases(IncludeDependentBases),
+ LoadExternal(LoadExternal) {}
+
+ void lookupVisibleDecls(Sema &SemaRef, Scope *S, Sema::LookupNameKind Kind,
+ bool IncludeGlobalScope) {
+ // Determine the set of using directives available during
+ // unqualified name lookup.
+ Scope *Initial = S;
+ UnqualUsingDirectiveSet UDirs(SemaRef);
+ if (SemaRef.getLangOpts().CPlusPlus) {
+ // Find the first namespace or translation-unit scope.
+ while (S && !isNamespaceOrTranslationUnitScope(S))
+ S = S->getParent();
- // Walk all lookup results in the TU for each identifier.
- for (const auto &Ident : Idents) {
- for (auto I = S.IdResolver.begin(Ident.getValue()),
- E = S.IdResolver.end();
- I != E; ++I) {
- if (S.IdResolver.isDeclInScope(*I, Ctx)) {
- if (NamedDecl *ND = Result.getAcceptableDecl(*I)) {
- Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
- Visited.add(ND);
- }
- }
- }
+ UDirs.visitScopeChain(Initial, S);
}
+ UDirs.done();
- return;
+ // Look for visible declarations.
+ LookupResult Result(SemaRef, DeclarationName(), SourceLocation(), Kind);
+ Result.setAllowHidden(Consumer.includeHiddenDecls());
+ if (!IncludeGlobalScope)
+ Visited.visitedContext(SemaRef.getASTContext().getTranslationUnitDecl());
+ ShadowContextRAII Shadow(Visited);
+ lookupInScope(Initial, Result, UDirs);
}
- if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx))
- Result.getSema().ForceDeclarationOfImplicitMembers(Class);
+ void lookupVisibleDecls(Sema &SemaRef, DeclContext *Ctx,
+ Sema::LookupNameKind Kind, bool IncludeGlobalScope) {
+ LookupResult Result(SemaRef, DeclarationName(), SourceLocation(), Kind);
+ Result.setAllowHidden(Consumer.includeHiddenDecls());
+ if (!IncludeGlobalScope)
+ Visited.visitedContext(SemaRef.getASTContext().getTranslationUnitDecl());
- // We sometimes skip loading namespace-level results (they tend to be huge).
- bool Load = LoadExternal ||
- !(isa<TranslationUnitDecl>(Ctx) || isa<NamespaceDecl>(Ctx));
- // Enumerate all of the results in this context.
- for (DeclContextLookupResult R :
- Load ? Ctx->lookups()
- : Ctx->noload_lookups(/*PreserveInternalState=*/false)) {
- for (auto *D : R) {
- if (auto *ND = Result.getAcceptableDecl(D)) {
- Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
- Visited.add(ND);
- }
- }
- }
-
- // Traverse using directives for qualified name lookup.
- if (QualifiedNameLookup) {
ShadowContextRAII Shadow(Visited);
- for (auto I : Ctx->using_directives()) {
- if (!Result.getSema().isVisible(I))
- continue;
- LookupVisibleDecls(I->getNominatedNamespace(), Result,
- QualifiedNameLookup, InBaseClass, Consumer, Visited,
- IncludeDependentBases, LoadExternal);
- }
+ lookupInDeclContext(Ctx, Result, /*QualifiedNameLookup=*/true,
+ /*InBaseClass=*/false);
}
- // Traverse the contexts of inherited C++ classes.
- if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
- if (!Record->hasDefinition())
+private:
+ void lookupInDeclContext(DeclContext *Ctx, LookupResult &Result,
+ bool QualifiedNameLookup, bool InBaseClass) {
+ if (!Ctx)
return;
- for (const auto &B : Record->bases()) {
- QualType BaseType = B.getType();
+ // Make sure we don't visit the same context twice.
+ if (Visited.visitedContext(Ctx->getPrimaryContext()))
+ return;
- RecordDecl *RD;
- if (BaseType->isDependentType()) {
- if (!IncludeDependentBases) {
- // Don't look into dependent bases, because name lookup can't look
- // there anyway.
- continue;
+ Consumer.EnteredContext(Ctx);
+
+ // Outside C++, lookup results for the TU live on identifiers.
+ if (isa<TranslationUnitDecl>(Ctx) &&
+ !Result.getSema().getLangOpts().CPlusPlus) {
+ auto &S = Result.getSema();
+ auto &Idents = S.Context.Idents;
+
+ // Ensure all external identifiers are in the identifier table.
+ if (LoadExternal)
+ if (IdentifierInfoLookup *External =
+ Idents.getExternalIdentifierLookup()) {
+ std::unique_ptr<IdentifierIterator> Iter(External->getIdentifiers());
+ for (StringRef Name = Iter->Next(); !Name.empty();
+ Name = Iter->Next())
+ Idents.get(Name);
+ }
+
+ // Walk all lookup results in the TU for each identifier.
+ for (const auto &Ident : Idents) {
+ for (auto I = S.IdResolver.begin(Ident.getValue()),
+ E = S.IdResolver.end();
+ I != E; ++I) {
+ if (S.IdResolver.isDeclInScope(*I, Ctx)) {
+ if (NamedDecl *ND = Result.getAcceptableDecl(*I)) {
+ Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
+ Visited.add(ND);
+ }
+ }
}
- const auto *TST = BaseType->getAs<TemplateSpecializationType>();
- if (!TST)
- continue;
- TemplateName TN = TST->getTemplateName();
- const auto *TD =
- dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
- if (!TD)
- continue;
- RD = TD->getTemplatedDecl();
- } else {
- const auto *Record = BaseType->getAs<RecordType>();
- if (!Record)
- continue;
- RD = Record->getDecl();
}
- // FIXME: It would be nice to be able to determine whether referencing
- // a particular member would be ambiguous. For example, given
- //
- // struct A { int member; };
- // struct B { int member; };
- // struct C : A, B { };
- //
- // void f(C *c) { c->### }
- //
- // accessing 'member' would result in an ambiguity. However, we
- // could be smart enough to qualify the member with the base
- // class, e.g.,
- //
- // c->B::member
- //
- // or
- //
- // c->A::member
-
- // Find results in this base class (and its bases).
- ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(RD, Result, QualifiedNameLookup, /*InBaseClass=*/true,
- Consumer, Visited, IncludeDependentBases,
- LoadExternal);
+ return;
}
- }
- // Traverse the contexts of Objective-C classes.
- if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) {
- // Traverse categories.
- for (auto *Cat : IFace->visible_categories()) {
- ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(Cat, Result, QualifiedNameLookup, false, Consumer,
- Visited, IncludeDependentBases, LoadExternal);
+ if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx))
+ Result.getSema().ForceDeclarationOfImplicitMembers(Class);
+
+ // We sometimes skip loading namespace-level results (they tend to be huge).
+ bool Load = LoadExternal ||
+ !(isa<TranslationUnitDecl>(Ctx) || isa<NamespaceDecl>(Ctx));
+ // Enumerate all of the results in this context.
+ for (DeclContextLookupResult R :
+ Load ? Ctx->lookups()
+ : Ctx->noload_lookups(/*PreserveInternalState=*/false)) {
+ for (auto *D : R) {
+ if (auto *ND = Result.getAcceptableDecl(D)) {
+ Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
+ Visited.add(ND);
+ }
+ }
}
- // Traverse protocols.
- for (auto *I : IFace->all_referenced_protocols()) {
+ // Traverse using directives for qualified name lookup.
+ if (QualifiedNameLookup) {
ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer,
- Visited, IncludeDependentBases, LoadExternal);
+ for (auto I : Ctx->using_directives()) {
+ if (!Result.getSema().isVisible(I))
+ continue;
+ lookupInDeclContext(I->getNominatedNamespace(), Result,
+ QualifiedNameLookup, InBaseClass);
+ }
}
- // Traverse the superclass.
- if (IFace->getSuperClass()) {
- ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup,
- true, Consumer, Visited, IncludeDependentBases,
- LoadExternal);
- }
+ // Traverse the contexts of inherited C++ classes.
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
+ if (!Record->hasDefinition())
+ return;
- // If there is an implementation, traverse it. We do this to find
- // synthesized ivars.
- if (IFace->getImplementation()) {
- ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(IFace->getImplementation(), Result,
- QualifiedNameLookup, InBaseClass, Consumer, Visited,
- IncludeDependentBases, LoadExternal);
- }
- } else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) {
- for (auto *I : Protocol->protocols()) {
- ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer,
- Visited, IncludeDependentBases, LoadExternal);
- }
- } else if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Ctx)) {
- for (auto *I : Category->protocols()) {
- ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer,
- Visited, IncludeDependentBases, LoadExternal);
+ for (const auto &B : Record->bases()) {
+ QualType BaseType = B.getType();
+
+ RecordDecl *RD;
+ if (BaseType->isDependentType()) {
+ if (!IncludeDependentBases) {
+ // Don't look into dependent bases, because name lookup can't look
+ // there anyway.
+ continue;
+ }
+ const auto *TST = BaseType->getAs<TemplateSpecializationType>();
+ if (!TST)
+ continue;
+ TemplateName TN = TST->getTemplateName();
+ const auto *TD =
+ dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
+ if (!TD)
+ continue;
+ RD = TD->getTemplatedDecl();
+ } else {
+ const auto *Record = BaseType->getAs<RecordType>();
+ if (!Record)
+ continue;
+ RD = Record->getDecl();
+ }
+
+ // FIXME: It would be nice to be able to determine whether referencing
+ // a particular member would be ambiguous. For example, given
+ //
+ // struct A { int member; };
+ // struct B { int member; };
+ // struct C : A, B { };
+ //
+ // void f(C *c) { c->### }
+ //
+ // accessing 'member' would result in an ambiguity. However, we
+ // could be smart enough to qualify the member with the base
+ // class, e.g.,
+ //
+ // c->B::member
+ //
+ // or
+ //
+ // c->A::member
+
+ // Find results in this base class (and its bases).
+ ShadowContextRAII Shadow(Visited);
+ lookupInDeclContext(RD, Result, QualifiedNameLookup,
+ /*InBaseClass=*/true);
+ }
}
- // If there is an implementation, traverse it.
- if (Category->getImplementation()) {
- ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(Category->getImplementation(), Result,
- QualifiedNameLookup, true, Consumer, Visited,
- IncludeDependentBases, LoadExternal);
+ // Traverse the contexts of Objective-C classes.
+ if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) {
+ // Traverse categories.
+ for (auto *Cat : IFace->visible_categories()) {
+ ShadowContextRAII Shadow(Visited);
+ lookupInDeclContext(Cat, Result, QualifiedNameLookup,
+ /*InBaseClass=*/false);
+ }
+
+ // Traverse protocols.
+ for (auto *I : IFace->all_referenced_protocols()) {
+ ShadowContextRAII Shadow(Visited);
+ lookupInDeclContext(I, Result, QualifiedNameLookup,
+ /*InBaseClass=*/false);
+ }
+
+ // Traverse the superclass.
+ if (IFace->getSuperClass()) {
+ ShadowContextRAII Shadow(Visited);
+ lookupInDeclContext(IFace->getSuperClass(), Result, QualifiedNameLookup,
+ /*InBaseClass=*/true);
+ }
+
+ // If there is an implementation, traverse it. We do this to find
+ // synthesized ivars.
+ if (IFace->getImplementation()) {
+ ShadowContextRAII Shadow(Visited);
+ lookupInDeclContext(IFace->getImplementation(), Result,
+ QualifiedNameLookup, InBaseClass);
+ }
+ } else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) {
+ for (auto *I : Protocol->protocols()) {
+ ShadowContextRAII Shadow(Visited);
+ lookupInDeclContext(I, Result, QualifiedNameLookup,
+ /*InBaseClass=*/false);
+ }
+ } else if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Ctx)) {
+ for (auto *I : Category->protocols()) {
+ ShadowContextRAII Shadow(Visited);
+ lookupInDeclContext(I, Result, QualifiedNameLookup,
+ /*InBaseClass=*/false);
+ }
+
+ // If there is an implementation, traverse it.
+ if (Category->getImplementation()) {
+ ShadowContextRAII Shadow(Visited);
+ lookupInDeclContext(Category->getImplementation(), Result,
+ QualifiedNameLookup, /*InBaseClass=*/true);
+ }
}
}
-}
-static void LookupVisibleDecls(Scope *S, LookupResult &Result,
- UnqualUsingDirectiveSet &UDirs,
- VisibleDeclConsumer &Consumer,
- VisibleDeclsRecord &Visited,
- bool LoadExternal) {
- if (!S)
- return;
+ void lookupInScope(Scope *S, LookupResult &Result,
+ UnqualUsingDirectiveSet &UDirs) {
+ // No clients run in this mode and it's not supported. Please add tests and
+ // remove the assertion if you start relying on it.
+ assert(!IncludeDependentBases && "Unsupported flag for lookupInScope");
- if (!S->getEntity() ||
- (!S->getParent() &&
- !Visited.alreadyVisitedContext(S->getEntity())) ||
- (S->getEntity())->isFunctionOrMethod()) {
- FindLocalExternScope FindLocals(Result);
- // Walk through the declarations in this Scope. The consumer might add new
- // decls to the scope as part of deserialization, so make a copy first.
- SmallVector<Decl *, 8> ScopeDecls(S->decls().begin(), S->decls().end());
- for (Decl *D : ScopeDecls) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
- if ((ND = Result.getAcceptableDecl(ND))) {
- Consumer.FoundDecl(ND, Visited.checkHidden(ND), nullptr, false);
- Visited.add(ND);
- }
+ if (!S)
+ return;
+
+ if (!S->getEntity() ||
+ (!S->getParent() && !Visited.alreadyVisitedContext(S->getEntity())) ||
+ (S->getEntity())->isFunctionOrMethod()) {
+ FindLocalExternScope FindLocals(Result);
+ // Walk through the declarations in this Scope. The consumer might add new
+ // decls to the scope as part of deserialization, so make a copy first.
+ SmallVector<Decl *, 8> ScopeDecls(S->decls().begin(), S->decls().end());
+ for (Decl *D : ScopeDecls) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ if ((ND = Result.getAcceptableDecl(ND))) {
+ Consumer.FoundDecl(ND, Visited.checkHidden(ND), nullptr, false);
+ Visited.add(ND);
+ }
+ }
}
- }
- // FIXME: C++ [temp.local]p8
- DeclContext *Entity = nullptr;
- if (S->getEntity()) {
- // Look into this scope's declaration context, along with any of its
- // parent lookup contexts (e.g., enclosing classes), up to the point
- // where we hit the context stored in the next outer scope.
- Entity = S->getEntity();
- DeclContext *OuterCtx = findOuterContext(S).first; // FIXME
-
- for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx);
- Ctx = Ctx->getLookupParent()) {
- if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) {
- if (Method->isInstanceMethod()) {
- // For instance methods, look for ivars in the method's interface.
- LookupResult IvarResult(Result.getSema(), Result.getLookupName(),
- Result.getNameLoc(), Sema::LookupMemberName);
- if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) {
- LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false,
- /*InBaseClass=*/false, Consumer, Visited,
- /*IncludeDependentBases=*/false, LoadExternal);
+ // FIXME: C++ [temp.local]p8
+ DeclContext *Entity = nullptr;
+ if (S->getEntity()) {
+ // Look into this scope's declaration context, along with any of its
+ // parent lookup contexts (e.g., enclosing classes), up to the point
+ // where we hit the context stored in the next outer scope.
+ Entity = S->getEntity();
+ DeclContext *OuterCtx = findOuterContext(S).first; // FIXME
+
+ for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx);
+ Ctx = Ctx->getLookupParent()) {
+ if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) {
+ if (Method->isInstanceMethod()) {
+ // For instance methods, look for ivars in the method's interface.
+ LookupResult IvarResult(Result.getSema(), Result.getLookupName(),
+ Result.getNameLoc(),
+ Sema::LookupMemberName);
+ if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) {
+ lookupInDeclContext(IFace, IvarResult,
+ /*QualifiedNameLookup=*/false,
+ /*InBaseClass=*/false);
+ }
}
+
+ // We've already performed all of the name lookup that we need
+ // to for Objective-C methods; the next context will be the
+ // outer scope.
+ break;
}
- // We've already performed all of the name lookup that we need
- // to for Objective-C methods; the next context will be the
- // outer scope.
- break;
- }
+ if (Ctx->isFunctionOrMethod())
+ continue;
- if (Ctx->isFunctionOrMethod())
- continue;
+ lookupInDeclContext(Ctx, Result, /*QualifiedNameLookup=*/false,
+ /*InBaseClass=*/false);
+ }
+ } else if (!S->getParent()) {
+ // Look into the translation unit scope. We walk through the translation
+ // unit's declaration context, because the Scope itself won't have all of
+ // the declarations if we loaded a precompiled header.
+ // FIXME: We would like the translation unit's Scope object to point to
+ // the translation unit, so we don't need this special "if" branch.
+ // However, doing so would force the normal C++ name-lookup code to look
+ // into the translation unit decl when the IdentifierInfo chains would
+ // suffice. Once we fix that problem (which is part of a more general
+ // "don't look in DeclContexts unless we have to" optimization), we can
+ // eliminate this.
+ Entity = Result.getSema().Context.getTranslationUnitDecl();
+ lookupInDeclContext(Entity, Result, /*QualifiedNameLookup=*/false,
+ /*InBaseClass=*/false);
+ }
- LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false,
- /*InBaseClass=*/false, Consumer, Visited,
- /*IncludeDependentBases=*/false, LoadExternal);
+ if (Entity) {
+ // Lookup visible declarations in any namespaces found by using
+ // directives.
+ for (const UnqualUsingEntry &UUE : UDirs.getNamespacesFor(Entity))
+ lookupInDeclContext(
+ const_cast<DeclContext *>(UUE.getNominatedNamespace()), Result,
+ /*QualifiedNameLookup=*/false,
+ /*InBaseClass=*/false);
}
- } else if (!S->getParent()) {
- // Look into the translation unit scope. We walk through the translation
- // unit's declaration context, because the Scope itself won't have all of
- // the declarations if we loaded a precompiled header.
- // FIXME: We would like the translation unit's Scope object to point to the
- // translation unit, so we don't need this special "if" branch. However,
- // doing so would force the normal C++ name-lookup code to look into the
- // translation unit decl when the IdentifierInfo chains would suffice.
- // Once we fix that problem (which is part of a more general "don't look
- // in DeclContexts unless we have to" optimization), we can eliminate this.
- Entity = Result.getSema().Context.getTranslationUnitDecl();
- LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false,
- /*InBaseClass=*/false, Consumer, Visited,
- /*IncludeDependentBases=*/false, LoadExternal);
- }
- if (Entity) {
- // Lookup visible declarations in any namespaces found by using
- // directives.
- for (const UnqualUsingEntry &UUE : UDirs.getNamespacesFor(Entity))
- LookupVisibleDecls(const_cast<DeclContext *>(UUE.getNominatedNamespace()),
- Result, /*QualifiedNameLookup=*/false,
- /*InBaseClass=*/false, Consumer, Visited,
- /*IncludeDependentBases=*/false, LoadExternal);
+ // Lookup names in the parent scope.
+ ShadowContextRAII Shadow(Visited);
+ lookupInScope(S->getParent(), Result, UDirs);
}
- // Lookup names in the parent scope.
- ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(S->getParent(), Result, UDirs, Consumer, Visited,
- LoadExternal);
-}
+private:
+ VisibleDeclsRecord Visited;
+ VisibleDeclConsumer &Consumer;
+ bool IncludeDependentBases;
+ bool LoadExternal;
+};
+} // namespace
void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind,
VisibleDeclConsumer &Consumer,
bool IncludeGlobalScope, bool LoadExternal) {
- // Determine the set of using directives available during
- // unqualified name lookup.
- Scope *Initial = S;
- UnqualUsingDirectiveSet UDirs(*this);
- if (getLangOpts().CPlusPlus) {
- // Find the first namespace or translation-unit scope.
- while (S && !isNamespaceOrTranslationUnitScope(S))
- S = S->getParent();
-
- UDirs.visitScopeChain(Initial, S);
- }
- UDirs.done();
-
- // Look for visible declarations.
- LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind);
- Result.setAllowHidden(Consumer.includeHiddenDecls());
- VisibleDeclsRecord Visited;
- if (!IncludeGlobalScope)
- Visited.visitedContext(Context.getTranslationUnitDecl());
- ShadowContextRAII Shadow(Visited);
- ::LookupVisibleDecls(Initial, Result, UDirs, Consumer, Visited, LoadExternal);
+ LookupVisibleHelper H(Consumer, /*IncludeDependentBases=*/false,
+ LoadExternal);
+ H.lookupVisibleDecls(*this, S, Kind, IncludeGlobalScope);
}
void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
VisibleDeclConsumer &Consumer,
bool IncludeGlobalScope,
bool IncludeDependentBases, bool LoadExternal) {
- LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind);
- Result.setAllowHidden(Consumer.includeHiddenDecls());
- VisibleDeclsRecord Visited;
- if (!IncludeGlobalScope)
- Visited.visitedContext(Context.getTranslationUnitDecl());
- ShadowContextRAII Shadow(Visited);
- ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true,
- /*InBaseClass=*/false, Consumer, Visited,
- IncludeDependentBases, LoadExternal);
+ LookupVisibleHelper H(Consumer, IncludeDependentBases, LoadExternal);
+ H.lookupVisibleDecls(*this, Ctx, Kind, IncludeGlobalScope);
}
/// LookupOrCreateLabel - Do a name lookup of a label with the specified name.
@@ -4745,7 +4863,7 @@ std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer(
// occurs). Note that CorrectionCandidateCallback is polymorphic and
// initially stack-allocated.
std::unique_ptr<CorrectionCandidateCallback> ClonedCCC = CCC.clone();
- auto Consumer = llvm::make_unique<TypoCorrectionConsumer>(
+ auto Consumer = std::make_unique<TypoCorrectionConsumer>(
*this, TypoName, LookupKind, S, SS, std::move(ClonedCCC), MemberContext,
EnteringContext);
@@ -5164,8 +5282,11 @@ static NamedDecl *getDefinitionToImport(NamedDecl *D) {
return FD->getDefinition();
if (TagDecl *TD = dyn_cast<TagDecl>(D))
return TD->getDefinition();
+ // The first definition for this ObjCInterfaceDecl might be in the TU
+ // and not associated with any module. Use the one we know to be complete
+ // and have just seen in a module.
if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
- return ID->getDefinition();
+ return ID;
if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
return PD->getDefinition();
if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D))
@@ -5361,6 +5482,8 @@ TypoExpr *Sema::createDelayedTypo(std::unique_ptr<TypoCorrectionConsumer> TCC,
State.Consumer = std::move(TCC);
State.DiagHandler = std::move(TDG);
State.RecoveryHandler = std::move(TRC);
+ if (TE)
+ TypoExprs.push_back(TE);
return TE;
}
diff --git a/lib/Sema/SemaModule.cpp b/lib/Sema/SemaModule.cpp
index 10de0ca91221..1fca351bfb09 100644
--- a/lib/Sema/SemaModule.cpp
+++ b/lib/Sema/SemaModule.cpp
@@ -31,6 +31,8 @@ static void checkModuleImportContext(Sema &S, Module *M,
ExternCLoc = LSD->getBeginLoc();
break;
case LinkageSpecDecl::lang_cxx:
+ case LinkageSpecDecl::lang_cxx_11:
+ case LinkageSpecDecl::lang_cxx_14:
break;
}
DC = LSD->getParent();
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index e5c014501431..ac810745d2f5 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -735,7 +735,7 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,
return;
// If the ivar is private, and it's implicitly __unsafe_unretained
- // becaues of its type, then pretend it was actually implicitly
+ // because of its type, then pretend it was actually implicitly
// __strong. This is only sound because we're processing the
// property implementation before parsing any method bodies.
if (ivarLifetime == Qualifiers::OCL_ExplicitNone &&
@@ -2419,9 +2419,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
ObjCReturnsInnerPointerAttr::CreateImplicit(Context, Loc));
if (const SectionAttr *SA = property->getAttr<SectionAttr>())
- GetterMethod->addAttr(
- SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section,
- SA->getName(), Loc));
+ GetterMethod->addAttr(SectionAttr::CreateImplicit(
+ Context, SA->getName(), Loc, AttributeCommonInfo::AS_GNU,
+ SectionAttr::GNU_section));
if (getLangOpts().ObjCAutoRefCount)
CheckARCMethodDecl(GetterMethod);
@@ -2485,9 +2485,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
CD->addDecl(SetterMethod);
if (const SectionAttr *SA = property->getAttr<SectionAttr>())
- SetterMethod->addAttr(
- SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section,
- SA->getName(), Loc));
+ SetterMethod->addAttr(SectionAttr::CreateImplicit(
+ Context, SA->getName(), Loc, AttributeCommonInfo::AS_GNU,
+ SectionAttr::GNU_section));
// It's possible for the user to have set a very odd custom
// setter selector that causes it to have a method family.
if (getLangOpts().ObjCAutoRefCount)
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index bd68011c18b2..c7e0d2aee036 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -139,6 +139,7 @@ private:
/// clause, false otherwise.
llvm::Optional<std::pair<const Expr *, OMPOrderedClause *>> OrderedRegion;
unsigned AssociatedLoops = 1;
+ bool HasMutipleLoops = false;
const Decl *PossiblyLoopCounter = nullptr;
bool NowaitRegion = false;
bool CancelRegion = false;
@@ -169,7 +170,7 @@ private:
OpenMPClauseKind ClauseKindMode = OMPC_unknown;
Sema &SemaRef;
bool ForceCapturing = false;
- /// true if all the vaiables in the target executable directives must be
+ /// true if all the variables in the target executable directives must be
/// captured by reference.
bool ForceCaptureByReferenceInTargetExecutable = false;
CriticalsWithHintsTy Criticals;
@@ -521,6 +522,13 @@ public:
assert(!isStackEmpty() && "No directive at specified level.");
return getStackElemAtLevel(Level).Directive;
}
+ /// Returns the capture region at the specified level.
+ OpenMPDirectiveKind getCaptureRegion(unsigned Level,
+ unsigned OpenMPCaptureLevel) const {
+ SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
+ getOpenMPCaptureRegions(CaptureRegions, getDirective(Level));
+ return CaptureRegions[OpenMPCaptureLevel];
+ }
/// Returns parent directive.
OpenMPDirectiveKind getParentDirective() const {
const SharingMapTy *Parent = getSecondOnStackOrNull();
@@ -678,12 +686,19 @@ public:
/// Set collapse value for the region.
void setAssociatedLoops(unsigned Val) {
getTopOfStack().AssociatedLoops = Val;
+ if (Val > 1)
+ getTopOfStack().HasMutipleLoops = true;
}
/// Return collapse value for region.
unsigned getAssociatedLoops() const {
const SharingMapTy *Top = getTopOfStackOrNull();
return Top ? Top->AssociatedLoops : 0;
}
+ /// Returns true if the construct is associated with multiple loops.
+ bool hasMutipleLoops() const {
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ return Top ? Top->HasMutipleLoops : false;
+ }
/// Marks current target region as one with closely nested teams
/// region.
@@ -951,7 +966,8 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter,
// In a parallel construct, if no default clause is present, these
// variables are shared.
DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
- if (isOpenMPParallelDirective(DVar.DKind) ||
+ if ((isOpenMPParallelDirective(DVar.DKind) &&
+ !isOpenMPTaskLoopDirective(DVar.DKind)) ||
isOpenMPTeamsDirective(DVar.DKind)) {
DVar.CKind = OMPC_shared;
return DVar;
@@ -1332,7 +1348,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
}
const_iterator End = end();
if (!SemaRef.isOpenMPCapturedByRef(
- D, std::distance(ParentIterTarget, End))) {
+ D, std::distance(ParentIterTarget, End),
+ /*OpenMPCaptureLevel=*/0)) {
DVar.RefExpr =
buildDeclRefExpr(SemaRef, VD, D->getType().getNonReferenceType(),
IterTarget->ConstructLoc);
@@ -1540,49 +1557,150 @@ static bool isOpenMPDeviceDelayedContext(Sema &S) {
!S.isInOpenMPDeclareTargetContext();
}
-/// Do we know that we will eventually codegen the given function?
-static bool isKnownEmitted(Sema &S, FunctionDecl *FD) {
- assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsDevice &&
- "Expected OpenMP device compilation.");
- // Templates are emitted when they're instantiated.
- if (FD->isDependentContext())
- return false;
-
- if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(
- FD->getCanonicalDecl()))
- return true;
-
- // Otherwise, the function is known-emitted if it's in our set of
- // known-emitted functions.
- return S.DeviceKnownEmittedFns.count(FD) > 0;
-}
+namespace {
+/// Status of the function emission on the host/device.
+enum class FunctionEmissionStatus {
+ Emitted,
+ Discarded,
+ Unknown,
+};
+} // anonymous namespace
Sema::DeviceDiagBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc,
unsigned DiagID) {
assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice &&
"Expected OpenMP device compilation.");
- return DeviceDiagBuilder((isOpenMPDeviceDelayedContext(*this) &&
- !isKnownEmitted(*this, getCurFunctionDecl()))
- ? DeviceDiagBuilder::K_Deferred
- : DeviceDiagBuilder::K_Immediate,
- Loc, DiagID, getCurFunctionDecl(), *this);
+ FunctionEmissionStatus FES = getEmissionStatus(getCurFunctionDecl());
+ DeviceDiagBuilder::Kind Kind = DeviceDiagBuilder::K_Nop;
+ switch (FES) {
+ case FunctionEmissionStatus::Emitted:
+ Kind = DeviceDiagBuilder::K_Immediate;
+ break;
+ case FunctionEmissionStatus::Unknown:
+ Kind = isOpenMPDeviceDelayedContext(*this) ? DeviceDiagBuilder::K_Deferred
+ : DeviceDiagBuilder::K_Immediate;
+ break;
+ case FunctionEmissionStatus::TemplateDiscarded:
+ case FunctionEmissionStatus::OMPDiscarded:
+ Kind = DeviceDiagBuilder::K_Nop;
+ break;
+ case FunctionEmissionStatus::CUDADiscarded:
+ llvm_unreachable("CUDADiscarded unexpected in OpenMP device compilation");
+ break;
+ }
+
+ return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this);
}
-void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) {
+Sema::DeviceDiagBuilder Sema::diagIfOpenMPHostCode(SourceLocation Loc,
+ unsigned DiagID) {
+ assert(LangOpts.OpenMP && !LangOpts.OpenMPIsDevice &&
+ "Expected OpenMP host compilation.");
+ FunctionEmissionStatus FES = getEmissionStatus(getCurFunctionDecl());
+ DeviceDiagBuilder::Kind Kind = DeviceDiagBuilder::K_Nop;
+ switch (FES) {
+ case FunctionEmissionStatus::Emitted:
+ Kind = DeviceDiagBuilder::K_Immediate;
+ break;
+ case FunctionEmissionStatus::Unknown:
+ Kind = DeviceDiagBuilder::K_Deferred;
+ break;
+ case FunctionEmissionStatus::TemplateDiscarded:
+ case FunctionEmissionStatus::OMPDiscarded:
+ case FunctionEmissionStatus::CUDADiscarded:
+ Kind = DeviceDiagBuilder::K_Nop;
+ break;
+ }
+
+ return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this);
+}
+
+void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee,
+ bool CheckForDelayedContext) {
assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice &&
"Expected OpenMP device compilation.");
assert(Callee && "Callee may not be null.");
+ Callee = Callee->getMostRecentDecl();
FunctionDecl *Caller = getCurFunctionDecl();
+ // host only function are not available on the device.
+ if (Caller) {
+ FunctionEmissionStatus CallerS = getEmissionStatus(Caller);
+ FunctionEmissionStatus CalleeS = getEmissionStatus(Callee);
+ assert(CallerS != FunctionEmissionStatus::CUDADiscarded &&
+ CalleeS != FunctionEmissionStatus::CUDADiscarded &&
+ "CUDADiscarded unexpected in OpenMP device function check");
+ if ((CallerS == FunctionEmissionStatus::Emitted ||
+ (!isOpenMPDeviceDelayedContext(*this) &&
+ CallerS == FunctionEmissionStatus::Unknown)) &&
+ CalleeS == FunctionEmissionStatus::OMPDiscarded) {
+ StringRef HostDevTy = getOpenMPSimpleClauseTypeName(
+ OMPC_device_type, OMPC_DEVICE_TYPE_host);
+ Diag(Loc, diag::err_omp_wrong_device_function_call) << HostDevTy << 0;
+ Diag(Callee->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
+ diag::note_omp_marked_device_type_here)
+ << HostDevTy;
+ return;
+ }
+ }
// If the caller is known-emitted, mark the callee as known-emitted.
// Otherwise, mark the call in our call graph so we can traverse it later.
- if (!isOpenMPDeviceDelayedContext(*this) ||
- (Caller && isKnownEmitted(*this, Caller)))
- markKnownEmitted(*this, Caller, Callee, Loc, isKnownEmitted);
+ if ((CheckForDelayedContext && !isOpenMPDeviceDelayedContext(*this)) ||
+ (!Caller && !CheckForDelayedContext) ||
+ (Caller && getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted))
+ markKnownEmitted(*this, Caller, Callee, Loc,
+ [CheckForDelayedContext](Sema &S, FunctionDecl *FD) {
+ return CheckForDelayedContext &&
+ S.getEmissionStatus(FD) ==
+ FunctionEmissionStatus::Emitted;
+ });
else if (Caller)
DeviceCallGraph[Caller].insert({Callee, Loc});
}
+void Sema::checkOpenMPHostFunction(SourceLocation Loc, FunctionDecl *Callee,
+ bool CheckCaller) {
+ assert(LangOpts.OpenMP && !LangOpts.OpenMPIsDevice &&
+ "Expected OpenMP host compilation.");
+ assert(Callee && "Callee may not be null.");
+ Callee = Callee->getMostRecentDecl();
+ FunctionDecl *Caller = getCurFunctionDecl();
+
+ // device only function are not available on the host.
+ if (Caller) {
+ FunctionEmissionStatus CallerS = getEmissionStatus(Caller);
+ FunctionEmissionStatus CalleeS = getEmissionStatus(Callee);
+ assert(
+ (LangOpts.CUDA || (CallerS != FunctionEmissionStatus::CUDADiscarded &&
+ CalleeS != FunctionEmissionStatus::CUDADiscarded)) &&
+ "CUDADiscarded unexpected in OpenMP host function check");
+ if (CallerS == FunctionEmissionStatus::Emitted &&
+ CalleeS == FunctionEmissionStatus::OMPDiscarded) {
+ StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName(
+ OMPC_device_type, OMPC_DEVICE_TYPE_nohost);
+ Diag(Loc, diag::err_omp_wrong_device_function_call) << NoHostDevTy << 1;
+ Diag(Callee->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
+ diag::note_omp_marked_device_type_here)
+ << NoHostDevTy;
+ return;
+ }
+ }
+ // If the caller is known-emitted, mark the callee as known-emitted.
+ // Otherwise, mark the call in our call graph so we can traverse it later.
+ if (!shouldIgnoreInHostDeviceCheck(Callee)) {
+ if ((!CheckCaller && !Caller) ||
+ (Caller &&
+ getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted))
+ markKnownEmitted(
+ *this, Caller, Callee, Loc, [CheckCaller](Sema &S, FunctionDecl *FD) {
+ return CheckCaller &&
+ S.getEmissionStatus(FD) == FunctionEmissionStatus::Emitted;
+ });
+ else if (Caller)
+ DeviceCallGraph[Caller].insert({Callee, Loc});
+ }
+}
+
void Sema::checkOpenMPDeviceExpr(const Expr *E) {
assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice &&
"OpenMP device compilation mode is expected.");
@@ -1598,7 +1716,8 @@ void Sema::checkOpenMPDeviceExpr(const Expr *E) {
<< Context.getTargetInfo().getTriple().str() << E->getSourceRange();
}
-bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
+bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
+ unsigned OpenMPCaptureLevel) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
ASTContext &Ctx = getASTContext();
@@ -1608,6 +1727,7 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
D = cast<ValueDecl>(D->getCanonicalDecl());
QualType Ty = D->getType();
+ bool IsVariableUsedInMapClause = false;
if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level)) {
// This table summarizes how a given variable should be passed to the device
// given its type and the clauses where it appears. This table is based on
@@ -1669,7 +1789,6 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
// Locate map clauses and see if the variable being captured is referred to
// in any of those clauses. Here we only care about variables, not fields,
// because fields are part of aggregates.
- bool IsVariableUsedInMapClause = false;
bool IsVariableAssociatedWithSection = false;
DSAStack->checkMappableExprComponentListsForDeclAtLevel(
@@ -1727,10 +1846,13 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
if (IsByRef && Ty.getNonReferenceType()->isScalarType()) {
IsByRef =
- !DSAStack->hasExplicitDSA(
- D,
- [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; },
- Level, /*NotLastprivate=*/true) &&
+ ((IsVariableUsedInMapClause &&
+ DSAStack->getCaptureRegion(Level, OpenMPCaptureLevel) ==
+ OMPD_target) ||
+ !DSAStack->hasExplicitDSA(
+ D,
+ [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; },
+ Level, /*NotLastprivate=*/true)) &&
// If the variable is artificial and must be captured by value - try to
// capture by value.
!(isa<OMPCapturedExprDecl>(D) && !D->hasAttr<OMPCaptureNoInitAttr>() &&
@@ -1788,7 +1910,8 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
if (isInOpenMPDeclareTargetContext()) {
// Try to mark variable as declare target if it is used in capturing
// regions.
- if (!OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
+ if (LangOpts.OpenMP <= 45 &&
+ !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
checkDeclIsAllowedInOpenMPTarget(nullptr, VD);
return nullptr;
} else if (isInOpenMPTargetExecutionDirective()) {
@@ -1858,6 +1981,14 @@ void Sema::startOpenMPLoop() {
DSAStack->loopInit();
}
+void Sema::startOpenMPCXXRangeFor() {
+ assert(LangOpts.OpenMP && "OpenMP must be enabled.");
+ if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
+ DSAStack->resetPossibleLoopCounter();
+ DSAStack->loopStart();
+ }
+}
+
bool Sema::isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
@@ -1874,6 +2005,13 @@ bool Sema::isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const {
!isOpenMPSimdDirective(DSAStack->getCurrentDirective()))
return true;
}
+ if (const auto *VD = dyn_cast<VarDecl>(D)) {
+ if (DSAStack->isThreadPrivate(const_cast<VarDecl *>(VD)) &&
+ DSAStack->isForceVarCapturing() &&
+ !DSAStack->hasExplicitDSA(
+ D, [](OpenMPClauseKind K) { return K == OMPC_copyin; }, Level))
+ return true;
+ }
return DSAStack->hasExplicitDSA(
D, [](OpenMPClauseKind K) { return K == OMPC_private; }, Level) ||
(DSAStack->isClauseParsingMode() &&
@@ -1937,6 +2075,54 @@ bool Sema::isOpenMPTargetCapturedDecl(const ValueDecl *D,
void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; }
+void Sema::finalizeOpenMPDelayedAnalysis() {
+ assert(LangOpts.OpenMP && "Expected OpenMP compilation mode.");
+ // Diagnose implicit declare target functions and their callees.
+ for (const auto &CallerCallees : DeviceCallGraph) {
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(
+ CallerCallees.getFirst()->getMostRecentDecl());
+ // Ignore host functions during device analyzis.
+ if (LangOpts.OpenMPIsDevice && DevTy &&
+ *DevTy == OMPDeclareTargetDeclAttr::DT_Host)
+ continue;
+ // Ignore nohost functions during host analyzis.
+ if (!LangOpts.OpenMPIsDevice && DevTy &&
+ *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost)
+ continue;
+ for (const std::pair<CanonicalDeclPtr<FunctionDecl>, SourceLocation>
+ &Callee : CallerCallees.getSecond()) {
+ const FunctionDecl *FD = Callee.first->getMostRecentDecl();
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(FD);
+ if (LangOpts.OpenMPIsDevice && DevTy &&
+ *DevTy == OMPDeclareTargetDeclAttr::DT_Host) {
+ // Diagnose host function called during device codegen.
+ StringRef HostDevTy = getOpenMPSimpleClauseTypeName(
+ OMPC_device_type, OMPC_DEVICE_TYPE_host);
+ Diag(Callee.second, diag::err_omp_wrong_device_function_call)
+ << HostDevTy << 0;
+ Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
+ diag::note_omp_marked_device_type_here)
+ << HostDevTy;
+ continue;
+ }
+ if (!LangOpts.OpenMPIsDevice && DevTy &&
+ *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) {
+ // Diagnose nohost function called during host codegen.
+ StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName(
+ OMPC_device_type, OMPC_DEVICE_TYPE_nohost);
+ Diag(Callee.second, diag::err_omp_wrong_device_function_call)
+ << NoHostDevTy << 1;
+ Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
+ diag::note_omp_marked_device_type_here)
+ << NoHostDevTy;
+ continue;
+ }
+ }
+ }
+}
+
void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind,
const DeclarationNameInfo &DirName,
Scope *CurScope, SourceLocation Loc) {
@@ -2034,7 +2220,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<VarDeclFilterCCC>(*this);
+ return std::make_unique<VarDeclFilterCCC>(*this);
}
};
@@ -2056,7 +2242,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<VarOrFuncDeclFilterCCC>(*this);
+ return std::make_unique<VarOrFuncDeclFilterCCC>(*this);
}
};
@@ -2944,18 +3130,19 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
+ Params, /*OpenMPCaptureLevel=*/0);
// Mark this captured region as inlined, because we don't use outlined
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
- Context, AlwaysInlineAttr::Keyword_forceinline));
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
Sema::CapturedParamNameType ParamsTarget[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
// Start a captured region for 'target' with no implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsTarget);
+ ParamsTarget, /*OpenMPCaptureLevel=*/1);
Sema::CapturedParamNameType ParamsTeamsOrParallel[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
std::make_pair(".bound_tid.", KmpInt32PtrTy),
@@ -2964,7 +3151,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
// Start a captured region for 'teams' or 'parallel'. Both regions have
// the same implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsTeamsOrParallel);
+ ParamsTeamsOrParallel, /*OpenMPCaptureLevel=*/2);
break;
}
case OMPD_target:
@@ -2988,14 +3175,16 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
+ Params, /*OpenMPCaptureLevel=*/0);
// Mark this captured region as inlined, because we don't use outlined
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
- Context, AlwaysInlineAttr::Keyword_forceinline));
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- std::make_pair(StringRef(), QualType()));
+ std::make_pair(StringRef(), QualType()),
+ /*OpenMPCaptureLevel=*/1);
break;
}
case OMPD_simd:
@@ -3044,11 +3233,14 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
- Context, AlwaysInlineAttr::Keyword_forceinline));
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
break;
}
case OMPD_taskloop:
- case OMPD_taskloop_simd: {
+ case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd: {
QualType KmpInt32Ty =
Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1)
.withConst();
@@ -3086,7 +3278,58 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
- Context, AlwaysInlineAttr::Keyword_forceinline));
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
+ break;
+ }
+ case OMPD_parallel_master_taskloop: {
+ QualType KmpInt32Ty =
+ Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1)
+ .withConst();
+ QualType KmpUInt64Ty =
+ Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0)
+ .withConst();
+ QualType KmpInt64Ty =
+ Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1)
+ .withConst();
+ QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict();
+ QualType KmpInt32PtrTy =
+ Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
+ Sema::CapturedParamNameType ParamsParallel[] = {
+ std::make_pair(".global_tid.", KmpInt32PtrTy),
+ std::make_pair(".bound_tid.", KmpInt32PtrTy),
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ // Start a captured region for 'parallel'.
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ ParamsParallel, /*OpenMPCaptureLevel=*/1);
+ QualType Args[] = {VoidPtrTy};
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.Variadic = true;
+ QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI);
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(".global_tid.", KmpInt32Ty),
+ std::make_pair(".part_id.", KmpInt32PtrTy),
+ std::make_pair(".privates.", VoidPtrTy),
+ std::make_pair(
+ ".copy_fn.",
+ Context.getPointerType(CopyFnType).withConst().withRestrict()),
+ std::make_pair(".task_t.", Context.VoidPtrTy.withConst()),
+ std::make_pair(".lb.", KmpUInt64Ty),
+ std::make_pair(".ub.", KmpUInt64Ty),
+ std::make_pair(".st.", KmpInt64Ty),
+ std::make_pair(".liter.", KmpInt32Ty),
+ std::make_pair(".reductions.", VoidPtrTy),
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params, /*OpenMPCaptureLevel=*/2);
+ // Mark this captured region as inlined, because we don't use outlined
+ // function directly.
+ getCurCapturedRegion()->TheCapturedDecl->addAttr(
+ AlwaysInlineAttr::CreateImplicit(
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
break;
}
case OMPD_distribute_parallel_for_simd:
@@ -3127,18 +3370,19 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
+ Params, /*OpenMPCaptureLevel=*/0);
// Mark this captured region as inlined, because we don't use outlined
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
- Context, AlwaysInlineAttr::Keyword_forceinline));
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
Sema::CapturedParamNameType ParamsTarget[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
// Start a captured region for 'target' with no implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsTarget);
+ ParamsTarget, /*OpenMPCaptureLevel=*/1);
Sema::CapturedParamNameType ParamsTeams[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
@@ -3147,7 +3391,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
};
// Start a captured region for 'target' with no implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsTeams);
+ ParamsTeams, /*OpenMPCaptureLevel=*/2);
Sema::CapturedParamNameType ParamsParallel[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
@@ -3159,7 +3403,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
// Start a captured region for 'teams' or 'parallel'. Both regions have
// the same implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsParallel);
+ ParamsParallel, /*OpenMPCaptureLevel=*/3);
break;
}
@@ -3176,7 +3420,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
};
// Start a captured region for 'target' with no implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsTeams);
+ ParamsTeams, /*OpenMPCaptureLevel=*/0);
Sema::CapturedParamNameType ParamsParallel[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
@@ -3188,7 +3432,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
// Start a captured region for 'teams' or 'parallel'. Both regions have
// the same implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsParallel);
+ ParamsParallel, /*OpenMPCaptureLevel=*/1);
break;
}
case OMPD_target_update:
@@ -3218,7 +3462,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
- Context, AlwaysInlineAttr::Keyword_forceinline));
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
break;
}
case OMPD_threadprivate:
@@ -3235,12 +3480,17 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_requires:
+ case OMPD_declare_variant:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
}
}
+int Sema::getNumberOfConstructScopes(unsigned Level) const {
+ return getOpenMPCaptureLevels(DSAStack->getDirective(Level));
+}
+
int Sema::getOpenMPCaptureLevels(OpenMPDirectiveKind DKind) {
SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
getOpenMPCaptureRegions(CaptureRegions, DKind);
@@ -3670,7 +3920,10 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
// OpenMP [2.16, Nesting of Regions]
// If specified, a teams construct must be contained within a target
// construct.
- NestingProhibited = ParentRegion != OMPD_target;
+ NestingProhibited =
+ (SemaRef.LangOpts.OpenMP <= 45 && ParentRegion != OMPD_target) ||
+ (SemaRef.LangOpts.OpenMP >= 50 && ParentRegion != OMPD_unknown &&
+ ParentRegion != OMPD_target);
OrphanSeen = ParentRegion == OMPD_unknown;
Recommend = ShouldBeInTargetRegion;
}
@@ -4214,6 +4467,22 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_taskloop);
break;
+ case OMPD_master_taskloop:
+ Res = ActOnOpenMPMasterTaskLoopDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ AllowedNameModifiers.push_back(OMPD_taskloop);
+ break;
+ case OMPD_master_taskloop_simd:
+ Res = ActOnOpenMPMasterTaskLoopSimdDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ AllowedNameModifiers.push_back(OMPD_taskloop);
+ break;
+ case OMPD_parallel_master_taskloop:
+ Res = ActOnOpenMPParallelMasterTaskLoopDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ AllowedNameModifiers.push_back(OMPD_taskloop);
+ AllowedNameModifiers.push_back(OMPD_parallel);
+ break;
case OMPD_distribute:
Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
@@ -4301,6 +4570,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_requires:
+ case OMPD_declare_variant:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
@@ -4326,18 +4596,22 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
continue;
case OMPC_schedule:
break;
+ case OMPC_grainsize:
+ case OMPC_num_tasks:
+ case OMPC_final:
+ case OMPC_priority:
+ // Do not analyze if no parent parallel directive.
+ if (isOpenMPParallelDirective(DSAStack->getCurrentDirective()))
+ break;
+ continue;
case OMPC_ordered:
case OMPC_device:
case OMPC_num_teams:
case OMPC_thread_limit:
- case OMPC_priority:
- case OMPC_grainsize:
- case OMPC_num_tasks:
case OMPC_hint:
case OMPC_collapse:
case OMPC_safelen:
case OMPC_simdlen:
- case OMPC_final:
case OMPC_default:
case OMPC_proc_bind:
case OMPC_private:
@@ -4381,6 +4655,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Unexpected clause");
}
for (Stmt *CC : C->children()) {
@@ -4437,8 +4713,10 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
if (!DG || DG.get().isNull())
return DeclGroupPtrTy();
+ const int SimdId = 0;
if (!DG.get().isSingleDecl()) {
- Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd);
+ Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd_variant)
+ << SimdId;
return DG;
}
Decl *ADecl = DG.get().getSingleDecl();
@@ -4447,7 +4725,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
auto *FD = dyn_cast<FunctionDecl>(ADecl);
if (!FD) {
- Diag(ADecl->getLocation(), diag::err_omp_function_expected);
+ Diag(ADecl->getLocation(), diag::err_omp_function_expected) << SimdId;
return DeclGroupPtrTy();
}
@@ -4669,7 +4947,266 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
const_cast<unsigned *>(LinModifiers.data()), LinModifiers.size(),
NewSteps.data(), NewSteps.size(), SR);
ADecl->addAttr(NewAttr);
- return ConvertDeclToDeclGroup(ADecl);
+ return DG;
+}
+
+Optional<std::pair<FunctionDecl *, Expr *>>
+Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
+ Expr *VariantRef, SourceRange SR) {
+ if (!DG || DG.get().isNull())
+ return None;
+
+ const int VariantId = 1;
+ // Must be applied only to single decl.
+ if (!DG.get().isSingleDecl()) {
+ Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd_variant)
+ << VariantId << SR;
+ return None;
+ }
+ Decl *ADecl = DG.get().getSingleDecl();
+ if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ADecl))
+ ADecl = FTD->getTemplatedDecl();
+
+ // Decl must be a function.
+ auto *FD = dyn_cast<FunctionDecl>(ADecl);
+ if (!FD) {
+ Diag(ADecl->getLocation(), diag::err_omp_function_expected)
+ << VariantId << SR;
+ return None;
+ }
+
+ auto &&HasMultiVersionAttributes = [](const FunctionDecl *FD) {
+ return FD->hasAttrs() &&
+ (FD->hasAttr<CPUDispatchAttr>() || FD->hasAttr<CPUSpecificAttr>() ||
+ FD->hasAttr<TargetAttr>());
+ };
+ // OpenMP is not compatible with CPU-specific attributes.
+ if (HasMultiVersionAttributes(FD)) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_incompat_attributes)
+ << SR;
+ return None;
+ }
+
+ // Allow #pragma omp declare variant only if the function is not used.
+ if (FD->isUsed(false))
+ Diag(SR.getBegin(), diag::warn_omp_declare_variant_after_used)
+ << FD->getLocation();
+
+ // Check if the function was emitted already.
+ const FunctionDecl *Definition;
+ if (!FD->isThisDeclarationADefinition() && FD->isDefined(Definition) &&
+ (LangOpts.EmitAllDecls || Context.DeclMustBeEmitted(Definition)))
+ Diag(SR.getBegin(), diag::warn_omp_declare_variant_after_emitted)
+ << FD->getLocation();
+
+ // The VariantRef must point to function.
+ if (!VariantRef) {
+ Diag(SR.getBegin(), diag::err_omp_function_expected) << VariantId;
+ return None;
+ }
+
+ // Do not check templates, wait until instantiation.
+ if (VariantRef->isTypeDependent() || VariantRef->isValueDependent() ||
+ VariantRef->containsUnexpandedParameterPack() ||
+ VariantRef->isInstantiationDependent() || FD->isDependentContext())
+ return std::make_pair(FD, VariantRef);
+
+ // Convert VariantRef expression to the type of the original function to
+ // resolve possible conflicts.
+ ExprResult VariantRefCast;
+ if (LangOpts.CPlusPlus) {
+ QualType FnPtrType;
+ auto *Method = dyn_cast<CXXMethodDecl>(FD);
+ if (Method && !Method->isStatic()) {
+ const Type *ClassType =
+ Context.getTypeDeclType(Method->getParent()).getTypePtr();
+ FnPtrType = Context.getMemberPointerType(FD->getType(), ClassType);
+ ExprResult ER;
+ {
+ // Build adrr_of unary op to correctly handle type checks for member
+ // functions.
+ Sema::TentativeAnalysisScope Trap(*this);
+ ER = CreateBuiltinUnaryOp(VariantRef->getBeginLoc(), UO_AddrOf,
+ VariantRef);
+ }
+ if (!ER.isUsable()) {
+ Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
+ << VariantId << VariantRef->getSourceRange();
+ return None;
+ }
+ VariantRef = ER.get();
+ } else {
+ FnPtrType = Context.getPointerType(FD->getType());
+ }
+ ImplicitConversionSequence ICS =
+ TryImplicitConversion(VariantRef, FnPtrType.getUnqualifiedType(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*InOverloadResolution=*/false,
+ /*CStyle=*/false,
+ /*AllowObjCWritebackConversion=*/false);
+ if (ICS.isFailure()) {
+ Diag(VariantRef->getExprLoc(),
+ diag::err_omp_declare_variant_incompat_types)
+ << VariantRef->getType() << FnPtrType << VariantRef->getSourceRange();
+ return None;
+ }
+ VariantRefCast = PerformImplicitConversion(
+ VariantRef, FnPtrType.getUnqualifiedType(), AA_Converting);
+ if (!VariantRefCast.isUsable())
+ return None;
+ // Drop previously built artificial addr_of unary op for member functions.
+ if (Method && !Method->isStatic()) {
+ Expr *PossibleAddrOfVariantRef = VariantRefCast.get();
+ if (auto *UO = dyn_cast<UnaryOperator>(
+ PossibleAddrOfVariantRef->IgnoreImplicit()))
+ VariantRefCast = UO->getSubExpr();
+ }
+ } else {
+ VariantRefCast = VariantRef;
+ }
+
+ ExprResult ER = CheckPlaceholderExpr(VariantRefCast.get());
+ if (!ER.isUsable() ||
+ !ER.get()->IgnoreParenImpCasts()->getType()->isFunctionType()) {
+ Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
+ << VariantId << VariantRef->getSourceRange();
+ return None;
+ }
+
+ // The VariantRef must point to function.
+ auto *DRE = dyn_cast<DeclRefExpr>(ER.get()->IgnoreParenImpCasts());
+ if (!DRE) {
+ Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
+ << VariantId << VariantRef->getSourceRange();
+ return None;
+ }
+ auto *NewFD = dyn_cast_or_null<FunctionDecl>(DRE->getDecl());
+ if (!NewFD) {
+ Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
+ << VariantId << VariantRef->getSourceRange();
+ return None;
+ }
+
+ // Check if variant function is not marked with declare variant directive.
+ if (NewFD->hasAttrs() && NewFD->hasAttr<OMPDeclareVariantAttr>()) {
+ Diag(VariantRef->getExprLoc(),
+ diag::warn_omp_declare_variant_marked_as_declare_variant)
+ << VariantRef->getSourceRange();
+ SourceRange SR =
+ NewFD->specific_attr_begin<OMPDeclareVariantAttr>()->getRange();
+ Diag(SR.getBegin(), diag::note_omp_marked_declare_variant_here) << SR;
+ return None;
+ }
+
+ enum DoesntSupport {
+ VirtFuncs = 1,
+ Constructors = 3,
+ Destructors = 4,
+ DeletedFuncs = 5,
+ DefaultedFuncs = 6,
+ ConstexprFuncs = 7,
+ ConstevalFuncs = 8,
+ };
+ if (const auto *CXXFD = dyn_cast<CXXMethodDecl>(FD)) {
+ if (CXXFD->isVirtual()) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
+ << VirtFuncs;
+ return None;
+ }
+
+ if (isa<CXXConstructorDecl>(FD)) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
+ << Constructors;
+ return None;
+ }
+
+ if (isa<CXXDestructorDecl>(FD)) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
+ << Destructors;
+ return None;
+ }
+ }
+
+ if (FD->isDeleted()) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
+ << DeletedFuncs;
+ return None;
+ }
+
+ if (FD->isDefaulted()) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
+ << DefaultedFuncs;
+ return None;
+ }
+
+ if (FD->isConstexpr()) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
+ << (NewFD->isConsteval() ? ConstevalFuncs : ConstexprFuncs);
+ return None;
+ }
+
+ // Check general compatibility.
+ if (areMultiversionVariantFunctionsCompatible(
+ FD, NewFD, PDiag(diag::err_omp_declare_variant_noproto),
+ PartialDiagnosticAt(
+ SR.getBegin(),
+ PDiag(diag::note_omp_declare_variant_specified_here) << SR),
+ PartialDiagnosticAt(
+ VariantRef->getExprLoc(),
+ PDiag(diag::err_omp_declare_variant_doesnt_support)),
+ PartialDiagnosticAt(VariantRef->getExprLoc(),
+ PDiag(diag::err_omp_declare_variant_diff)
+ << FD->getLocation()),
+ /*TemplatesSupported=*/true, /*ConstexprSupported=*/false,
+ /*CLinkageMayDiffer=*/true))
+ return None;
+ return std::make_pair(FD, cast<Expr>(DRE));
+}
+
+void Sema::ActOnOpenMPDeclareVariantDirective(
+ FunctionDecl *FD, Expr *VariantRef, SourceRange SR,
+ const Sema::OpenMPDeclareVariantCtsSelectorData &Data) {
+ if (Data.CtxSet == OMPDeclareVariantAttr::CtxSetUnknown ||
+ Data.Ctx == OMPDeclareVariantAttr::CtxUnknown)
+ return;
+ Expr *Score = nullptr;
+ OMPDeclareVariantAttr::ScoreType ST = OMPDeclareVariantAttr::ScoreUnknown;
+ if (Data.CtxScore.isUsable()) {
+ ST = OMPDeclareVariantAttr::ScoreSpecified;
+ Score = Data.CtxScore.get();
+ if (!Score->isTypeDependent() && !Score->isValueDependent() &&
+ !Score->isInstantiationDependent() &&
+ !Score->containsUnexpandedParameterPack()) {
+ llvm::APSInt Result;
+ ExprResult ICE = VerifyIntegerConstantExpression(Score, &Result);
+ if (ICE.isInvalid())
+ return;
+ }
+ }
+ auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit(
+ Context, VariantRef, Score, Data.CtxSet, ST, Data.Ctx,
+ Data.ImplVendors.begin(), Data.ImplVendors.size(), SR);
+ FD->addAttr(NewAttr);
+}
+
+void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc,
+ FunctionDecl *Func,
+ bool MightBeOdrUse) {
+ assert(LangOpts.OpenMP && "Expected OpenMP mode.");
+
+ if (!Func->isDependentContext() && Func->hasAttrs()) {
+ for (OMPDeclareVariantAttr *A :
+ Func->specific_attrs<OMPDeclareVariantAttr>()) {
+ // TODO: add checks for active OpenMP context where possible.
+ Expr *VariantRef = A->getVariantFuncRef();
+ auto *DRE = dyn_cast<DeclRefExpr>(VariantRef->IgnoreParenImpCasts());
+ auto *F = cast<FunctionDecl>(DRE->getDecl());
+ if (!F->isDefined() && F->isTemplateInstantiation())
+ InstantiateFunctionDefinition(Loc, F->getFirstDecl());
+ MarkFunctionReferenced(Loc, F, MightBeOdrUse);
+ }
+ }
}
StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
@@ -4694,6 +5231,54 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
}
namespace {
+/// Iteration space of a single for loop.
+struct LoopIterationSpace final {
+ /// True if the condition operator is the strict compare operator (<, > or
+ /// !=).
+ bool IsStrictCompare = false;
+ /// Condition of the loop.
+ Expr *PreCond = nullptr;
+ /// This expression calculates the number of iterations in the loop.
+ /// It is always possible to calculate it before starting the loop.
+ Expr *NumIterations = nullptr;
+ /// The loop counter variable.
+ Expr *CounterVar = nullptr;
+ /// Private loop counter variable.
+ Expr *PrivateCounterVar = nullptr;
+ /// This is initializer for the initial value of #CounterVar.
+ Expr *CounterInit = nullptr;
+ /// This is step for the #CounterVar used to generate its update:
+ /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration.
+ Expr *CounterStep = nullptr;
+ /// Should step be subtracted?
+ bool Subtract = false;
+ /// Source range of the loop init.
+ SourceRange InitSrcRange;
+ /// Source range of the loop condition.
+ SourceRange CondSrcRange;
+ /// Source range of the loop increment.
+ SourceRange IncSrcRange;
+ /// Minimum value that can have the loop control variable. Used to support
+ /// non-rectangular loops. Applied only for LCV with the non-iterator types,
+ /// since only such variables can be used in non-loop invariant expressions.
+ Expr *MinValue = nullptr;
+ /// Maximum value that can have the loop control variable. Used to support
+ /// non-rectangular loops. Applied only for LCV with the non-iterator type,
+ /// since only such variables can be used in non-loop invariant expressions.
+ Expr *MaxValue = nullptr;
+ /// true, if the lower bound depends on the outer loop control var.
+ bool IsNonRectangularLB = false;
+ /// true, if the upper bound depends on the outer loop control var.
+ bool IsNonRectangularUB = false;
+ /// Index of the loop this loop depends on and forms non-rectangular loop
+ /// nest.
+ unsigned LoopDependentIdx = 0;
+ /// Final condition for the non-rectangular loop nest support. It is used to
+ /// check that the number of iterations for this particular counter must be
+ /// finished.
+ Expr *FinalCondition = nullptr;
+};
+
/// Helper class for checking canonical form of the OpenMP loops and
/// extracting iteration space of each loop in the loop nest, that will be used
/// for IR generation.
@@ -4743,6 +5328,9 @@ class OpenMPIterationSpaceChecker {
Optional<unsigned> CondDependOnLC;
/// Checks if the provide statement depends on the loop counter.
Optional<unsigned> doesDependOnLoopCounter(const Stmt *S, bool IsInitializer);
+ /// Original condition required for checking of the exit condition for
+ /// non-rectangular loop.
+ Expr *Condition = nullptr;
public:
OpenMPIterationSpaceChecker(Sema &SemaRef, DSAStackTy &Stack,
@@ -4774,7 +5362,7 @@ public:
bool isStrictTestOp() const { return TestIsStrictOp; }
/// Build the expression to calculate the number of iterations.
Expr *buildNumIterations(
- Scope *S, const bool LimitedType,
+ Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const;
/// Build the precondition expression for the loops.
Expr *
@@ -4798,8 +5386,21 @@ public:
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures,
SourceLocation Loc, Expr *Inc = nullptr,
OverloadedOperatorKind OOK = OO_Amp);
+ /// Builds the minimum value for the loop counter.
+ std::pair<Expr *, Expr *> buildMinMaxValues(
+ Scope *S, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const;
+ /// Builds final condition for the non-rectangular loops.
+ Expr *buildFinalCondition(Scope *S) const;
/// Return true if any expression is dependent.
bool dependent() const;
+ /// Returns true if the initializer forms non-rectangular loop.
+ bool doesInitDependOnLC() const { return InitDependOnLC.hasValue(); }
+ /// Returns true if the condition forms non-rectangular loop.
+ bool doesCondDependOnLC() const { return CondDependOnLC.hasValue(); }
+ /// Returns index of the loop we depend on (starting from 1), or 0 otherwise.
+ unsigned getLoopDependentIdx() const {
+ return InitDependOnLC.getValueOr(CondDependOnLC.getValueOr(0));
+ }
private:
/// Check the right-hand side of an assignment in the increment
@@ -4998,9 +5599,9 @@ public:
return false;
}
bool VisitStmt(const Stmt *S) {
- bool Res = true;
+ bool Res = false;
for (const Stmt *Child : S->children())
- Res = Child && Visit(Child) && Res;
+ Res = (Child && Visit(Child)) || Res;
return Res;
}
explicit LoopCounterRefChecker(Sema &SemaRef, DSAStackTy &Stack,
@@ -5142,14 +5743,17 @@ static const ValueDecl *getInitLCDecl(const Expr *E) {
bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
// Check test-expr for canonical form, save upper-bound UB, flags for
// less/greater and for strict/non-strict comparison.
- // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following:
+ // OpenMP [2.9] Canonical loop form. Test-expr may be one of the following:
// var relational-op b
// b relational-op var
//
+ bool IneqCondIsCanonical = SemaRef.getLangOpts().OpenMP >= 50;
if (!S) {
- SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << LCDecl;
+ SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond)
+ << (IneqCondIsCanonical ? 1 : 0) << LCDecl;
return true;
}
+ Condition = S;
S = getExprAsWritten(S);
SourceLocation CondLoc = S->getBeginLoc();
if (auto *BO = dyn_cast<BinaryOperator>(S)) {
@@ -5164,12 +5768,11 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
(BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE),
(BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT),
BO->getSourceRange(), BO->getOperatorLoc());
- } else if (BO->getOpcode() == BO_NE)
- return setUB(getInitLCDecl(BO->getLHS()) == LCDecl ?
- BO->getRHS() : BO->getLHS(),
- /*LessOp=*/llvm::None,
- /*StrictOp=*/true,
- BO->getSourceRange(), BO->getOperatorLoc());
+ } else if (IneqCondIsCanonical && BO->getOpcode() == BO_NE)
+ return setUB(
+ getInitLCDecl(BO->getLHS()) == LCDecl ? BO->getRHS() : BO->getLHS(),
+ /*LessOp=*/llvm::None,
+ /*StrictOp=*/true, BO->getSourceRange(), BO->getOperatorLoc());
} else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(S)) {
if (CE->getNumArgs() == 2) {
auto Op = CE->getOperator();
@@ -5188,12 +5791,12 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
CE->getOperatorLoc());
break;
case OO_ExclaimEqual:
- return setUB(getInitLCDecl(CE->getArg(0)) == LCDecl ?
- CE->getArg(1) : CE->getArg(0),
- /*LessOp=*/llvm::None,
- /*StrictOp=*/true,
- CE->getSourceRange(),
- CE->getOperatorLoc());
+ if (IneqCondIsCanonical)
+ return setUB(getInitLCDecl(CE->getArg(0)) == LCDecl ? CE->getArg(1)
+ : CE->getArg(0),
+ /*LessOp=*/llvm::None,
+ /*StrictOp=*/true, CE->getSourceRange(),
+ CE->getOperatorLoc());
break;
default:
break;
@@ -5203,7 +5806,7 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
if (dependent() || SemaRef.CurContext->isDependentContext())
return false;
SemaRef.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond)
- << S->getSourceRange() << LCDecl;
+ << (IneqCondIsCanonical ? 1 : 0) << S->getSourceRange() << LCDecl;
return true;
}
@@ -5336,15 +5939,177 @@ tryBuildCapture(Sema &SemaRef, Expr *Capture,
/// Build the expression to calculate the number of iterations.
Expr *OpenMPIterationSpaceChecker::buildNumIterations(
- Scope *S, const bool LimitedType,
+ Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const {
ExprResult Diff;
QualType VarType = LCDecl->getType().getNonReferenceType();
if (VarType->isIntegerType() || VarType->isPointerType() ||
SemaRef.getLangOpts().CPlusPlus) {
+ Expr *LBVal = LB;
+ Expr *UBVal = UB;
+ // LB = TestIsLessOp.getValue() ? min(LB(MinVal), LB(MaxVal)) :
+ // max(LB(MinVal), LB(MaxVal))
+ if (InitDependOnLC) {
+ const LoopIterationSpace &IS =
+ ResultIterSpaces[ResultIterSpaces.size() - 1 -
+ InitDependOnLC.getValueOr(
+ CondDependOnLC.getValueOr(0))];
+ if (!IS.MinValue || !IS.MaxValue)
+ return nullptr;
+ // OuterVar = Min
+ ExprResult MinValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue);
+ if (!MinValue.isUsable())
+ return nullptr;
+
+ ExprResult LBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MinValue.get());
+ if (!LBMinVal.isUsable())
+ return nullptr;
+ // OuterVar = Min, LBVal
+ LBMinVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMinVal.get(), LBVal);
+ if (!LBMinVal.isUsable())
+ return nullptr;
+ // (OuterVar = Min, LBVal)
+ LBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMinVal.get());
+ if (!LBMinVal.isUsable())
+ return nullptr;
+
+ // OuterVar = Max
+ ExprResult MaxValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue);
+ if (!MaxValue.isUsable())
+ return nullptr;
+
+ ExprResult LBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MaxValue.get());
+ if (!LBMaxVal.isUsable())
+ return nullptr;
+ // OuterVar = Max, LBVal
+ LBMaxVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMaxVal.get(), LBVal);
+ if (!LBMaxVal.isUsable())
+ return nullptr;
+ // (OuterVar = Max, LBVal)
+ LBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMaxVal.get());
+ if (!LBMaxVal.isUsable())
+ return nullptr;
+
+ Expr *LBMin = tryBuildCapture(SemaRef, LBMinVal.get(), Captures).get();
+ Expr *LBMax = tryBuildCapture(SemaRef, LBMaxVal.get(), Captures).get();
+ if (!LBMin || !LBMax)
+ return nullptr;
+ // LB(MinVal) < LB(MaxVal)
+ ExprResult MinLessMaxRes =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_LT, LBMin, LBMax);
+ if (!MinLessMaxRes.isUsable())
+ return nullptr;
+ Expr *MinLessMax =
+ tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures).get();
+ if (!MinLessMax)
+ return nullptr;
+ if (TestIsLessOp.getValue()) {
+ // LB(MinVal) < LB(MaxVal) ? LB(MinVal) : LB(MaxVal) - min(LB(MinVal),
+ // LB(MaxVal))
+ ExprResult MinLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc,
+ MinLessMax, LBMin, LBMax);
+ if (!MinLB.isUsable())
+ return nullptr;
+ LBVal = MinLB.get();
+ } else {
+ // LB(MinVal) < LB(MaxVal) ? LB(MaxVal) : LB(MinVal) - max(LB(MinVal),
+ // LB(MaxVal))
+ ExprResult MaxLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc,
+ MinLessMax, LBMax, LBMin);
+ if (!MaxLB.isUsable())
+ return nullptr;
+ LBVal = MaxLB.get();
+ }
+ }
+ // UB = TestIsLessOp.getValue() ? max(UB(MinVal), UB(MaxVal)) :
+ // min(UB(MinVal), UB(MaxVal))
+ if (CondDependOnLC) {
+ const LoopIterationSpace &IS =
+ ResultIterSpaces[ResultIterSpaces.size() - 1 -
+ InitDependOnLC.getValueOr(
+ CondDependOnLC.getValueOr(0))];
+ if (!IS.MinValue || !IS.MaxValue)
+ return nullptr;
+ // OuterVar = Min
+ ExprResult MinValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue);
+ if (!MinValue.isUsable())
+ return nullptr;
+
+ ExprResult UBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MinValue.get());
+ if (!UBMinVal.isUsable())
+ return nullptr;
+ // OuterVar = Min, UBVal
+ UBMinVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMinVal.get(), UBVal);
+ if (!UBMinVal.isUsable())
+ return nullptr;
+ // (OuterVar = Min, UBVal)
+ UBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMinVal.get());
+ if (!UBMinVal.isUsable())
+ return nullptr;
+
+ // OuterVar = Max
+ ExprResult MaxValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue);
+ if (!MaxValue.isUsable())
+ return nullptr;
+
+ ExprResult UBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MaxValue.get());
+ if (!UBMaxVal.isUsable())
+ return nullptr;
+ // OuterVar = Max, UBVal
+ UBMaxVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMaxVal.get(), UBVal);
+ if (!UBMaxVal.isUsable())
+ return nullptr;
+ // (OuterVar = Max, UBVal)
+ UBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMaxVal.get());
+ if (!UBMaxVal.isUsable())
+ return nullptr;
+
+ Expr *UBMin = tryBuildCapture(SemaRef, UBMinVal.get(), Captures).get();
+ Expr *UBMax = tryBuildCapture(SemaRef, UBMaxVal.get(), Captures).get();
+ if (!UBMin || !UBMax)
+ return nullptr;
+ // UB(MinVal) > UB(MaxVal)
+ ExprResult MinGreaterMaxRes =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_GT, UBMin, UBMax);
+ if (!MinGreaterMaxRes.isUsable())
+ return nullptr;
+ Expr *MinGreaterMax =
+ tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), Captures).get();
+ if (!MinGreaterMax)
+ return nullptr;
+ if (TestIsLessOp.getValue()) {
+ // UB(MinVal) > UB(MaxVal) ? UB(MinVal) : UB(MaxVal) - max(UB(MinVal),
+ // UB(MaxVal))
+ ExprResult MaxUB = SemaRef.ActOnConditionalOp(
+ DefaultLoc, DefaultLoc, MinGreaterMax, UBMin, UBMax);
+ if (!MaxUB.isUsable())
+ return nullptr;
+ UBVal = MaxUB.get();
+ } else {
+ // UB(MinVal) > UB(MaxVal) ? UB(MaxVal) : UB(MinVal) - min(UB(MinVal),
+ // UB(MaxVal))
+ ExprResult MinUB = SemaRef.ActOnConditionalOp(
+ DefaultLoc, DefaultLoc, MinGreaterMax, UBMax, UBMin);
+ if (!MinUB.isUsable())
+ return nullptr;
+ UBVal = MinUB.get();
+ }
+ }
// Upper - Lower
- Expr *UBExpr = TestIsLessOp.getValue() ? UB : LB;
- Expr *LBExpr = TestIsLessOp.getValue() ? LB : UB;
+ Expr *UBExpr = TestIsLessOp.getValue() ? UBVal : LBVal;
+ Expr *LBExpr = TestIsLessOp.getValue() ? LBVal : UBVal;
Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get();
Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get();
if (!Upper || !Lower)
@@ -5431,12 +6196,142 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations(
return Diff.get();
}
+std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues(
+ Scope *S, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const {
+ // Do not build for iterators, they cannot be used in non-rectangular loop
+ // nests.
+ if (LCDecl->getType()->isRecordType())
+ return std::make_pair(nullptr, nullptr);
+ // If we subtract, the min is in the condition, otherwise the min is in the
+ // init value.
+ Expr *MinExpr = nullptr;
+ Expr *MaxExpr = nullptr;
+ Expr *LBExpr = TestIsLessOp.getValue() ? LB : UB;
+ Expr *UBExpr = TestIsLessOp.getValue() ? UB : LB;
+ bool LBNonRect = TestIsLessOp.getValue() ? InitDependOnLC.hasValue()
+ : CondDependOnLC.hasValue();
+ bool UBNonRect = TestIsLessOp.getValue() ? CondDependOnLC.hasValue()
+ : InitDependOnLC.hasValue();
+ Expr *Lower =
+ LBNonRect ? LBExpr : tryBuildCapture(SemaRef, LBExpr, Captures).get();
+ Expr *Upper =
+ UBNonRect ? UBExpr : tryBuildCapture(SemaRef, UBExpr, Captures).get();
+ if (!Upper || !Lower)
+ return std::make_pair(nullptr, nullptr);
+
+ if (TestIsLessOp.getValue())
+ MinExpr = Lower;
+ else
+ MaxExpr = Upper;
+
+ // Build minimum/maximum value based on number of iterations.
+ ExprResult Diff;
+ QualType VarType = LCDecl->getType().getNonReferenceType();
+
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower);
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // Upper - Lower [- 1]
+ if (TestIsStrictOp)
+ Diff = SemaRef.BuildBinOp(
+ S, DefaultLoc, BO_Sub, Diff.get(),
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // Upper - Lower [- 1] + Step
+ ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures);
+ if (!NewStep.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // Parentheses (for dumping/debugging purposes only).
+ Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // (Upper - Lower [- 1]) / Step
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // ((Upper - Lower [- 1]) / Step) * Step
+ // Parentheses (for dumping/debugging purposes only).
+ Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Mul, Diff.get(), NewStep.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // Convert to the original type or ptrdiff_t, if original type is pointer.
+ if (!VarType->isAnyPointerType() &&
+ !SemaRef.Context.hasSameType(Diff.get()->getType(), VarType)) {
+ Diff = SemaRef.PerformImplicitConversion(
+ Diff.get(), VarType, Sema::AA_Converting, /*AllowExplicit=*/true);
+ } else if (VarType->isAnyPointerType() &&
+ !SemaRef.Context.hasSameType(
+ Diff.get()->getType(),
+ SemaRef.Context.getUnsignedPointerDiffType())) {
+ Diff = SemaRef.PerformImplicitConversion(
+ Diff.get(), SemaRef.Context.getUnsignedPointerDiffType(),
+ Sema::AA_Converting, /*AllowExplicit=*/true);
+ }
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // Parentheses (for dumping/debugging purposes only).
+ Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ if (TestIsLessOp.getValue()) {
+ // MinExpr = Lower;
+ // MaxExpr = Lower + (((Upper - Lower [- 1]) / Step) * Step)
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Lower, Diff.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+ Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false);
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+ MaxExpr = Diff.get();
+ } else {
+ // MaxExpr = Upper;
+ // MinExpr = Upper - (((Upper - Lower [- 1]) / Step) * Step)
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Diff.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+ Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false);
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+ MinExpr = Diff.get();
+ }
+
+ return std::make_pair(MinExpr, MaxExpr);
+}
+
+Expr *OpenMPIterationSpaceChecker::buildFinalCondition(Scope *S) const {
+ if (InitDependOnLC || CondDependOnLC)
+ return Condition;
+ return nullptr;
+}
+
Expr *OpenMPIterationSpaceChecker::buildPreCond(
Scope *S, Expr *Cond,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const {
+ // Do not build a precondition when the condition/initialization is dependent
+ // to prevent pessimistic early loop exit.
+ // TODO: this can be improved by calculating min/max values but not sure that
+ // it will be very effective.
+ if (CondDependOnLC || InitDependOnLC)
+ return SemaRef.PerformImplicitConversion(
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get(),
+ SemaRef.Context.BoolTy, /*Action=*/Sema::AA_Casting,
+ /*AllowExplicit=*/true).get();
+
// Try to build LB <op> UB, where <op> is <, >, <=, or >=.
- bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics();
- SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true);
+ Sema::TentativeAnalysisScope Trap(SemaRef);
ExprResult NewLB = tryBuildCapture(SemaRef, LB, Captures);
ExprResult NewUB = tryBuildCapture(SemaRef, UB, Captures);
@@ -5456,7 +6351,7 @@ Expr *OpenMPIterationSpaceChecker::buildPreCond(
CondExpr.get(), SemaRef.Context.BoolTy, /*Action=*/Sema::AA_Casting,
/*AllowExplicit=*/true);
}
- SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress);
+
// Otherwise use original loop condition and evaluate it in runtime.
return CondExpr.isUsable() ? CondExpr.get() : Cond;
}
@@ -5561,36 +6456,6 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData(
return Diff.get();
}
-
-/// Iteration space of a single for loop.
-struct LoopIterationSpace final {
- /// True if the condition operator is the strict compare operator (<, > or
- /// !=).
- bool IsStrictCompare = false;
- /// Condition of the loop.
- Expr *PreCond = nullptr;
- /// This expression calculates the number of iterations in the loop.
- /// It is always possible to calculate it before starting the loop.
- Expr *NumIterations = nullptr;
- /// The loop counter variable.
- Expr *CounterVar = nullptr;
- /// Private loop counter variable.
- Expr *PrivateCounterVar = nullptr;
- /// This is initializer for the initial value of #CounterVar.
- Expr *CounterInit = nullptr;
- /// This is step for the #CounterVar used to generate its update:
- /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration.
- Expr *CounterStep = nullptr;
- /// Should step be subtracted?
- bool Subtract = false;
- /// Source range of the loop init.
- SourceRange InitSrcRange;
- /// Source range of the loop condition.
- SourceRange CondSrcRange;
- /// Source range of the loop increment.
- SourceRange IncSrcRange;
-};
-
} // namespace
void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
@@ -5604,13 +6469,14 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
if (!ISC.checkAndSetInit(Init, /*EmitDiags=*/false)) {
if (ValueDecl *D = ISC.getLoopDecl()) {
auto *VD = dyn_cast<VarDecl>(D);
+ DeclRefExpr *PrivateRef = nullptr;
if (!VD) {
if (VarDecl *Private = isOpenMPCapturedDecl(D)) {
VD = Private;
} else {
- DeclRefExpr *Ref = buildCapture(*this, D, ISC.getLoopDeclRefExpr(),
- /*WithInit=*/false);
- VD = cast<VarDecl>(Ref->getDecl());
+ PrivateRef = buildCapture(*this, D, ISC.getLoopDeclRefExpr(),
+ /*WithInit=*/false);
+ VD = cast<VarDecl>(PrivateRef->getDecl());
}
}
DSAStack->addLoopControlVariable(D, VD);
@@ -5623,6 +6489,51 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
Var->getType().getNonLValueExprType(Context),
ForLoc, /*RefersToCapture=*/true));
}
+ OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
+ // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables
+ // Referenced in a Construct, C/C++]. The loop iteration variable in the
+ // associated for-loop of a simd construct with just one associated
+ // for-loop may be listed in a linear clause with a constant-linear-step
+ // that is the increment of the associated for-loop. The loop iteration
+ // variable(s) in the associated for-loop(s) of a for or parallel for
+ // construct may be listed in a private or lastprivate clause.
+ DSAStackTy::DSAVarData DVar =
+ DSAStack->getTopDSA(D, /*FromParent=*/false);
+ // If LoopVarRefExpr is nullptr it means the corresponding loop variable
+ // is declared in the loop and it is predetermined as a private.
+ Expr *LoopDeclRefExpr = ISC.getLoopDeclRefExpr();
+ OpenMPClauseKind PredeterminedCKind =
+ isOpenMPSimdDirective(DKind)
+ ? (DSAStack->hasMutipleLoops() ? OMPC_lastprivate : OMPC_linear)
+ : OMPC_private;
+ if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
+ DVar.CKind != PredeterminedCKind && DVar.RefExpr &&
+ (LangOpts.OpenMP <= 45 || (DVar.CKind != OMPC_lastprivate &&
+ DVar.CKind != OMPC_private))) ||
+ ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop ||
+ DKind == OMPD_master_taskloop ||
+ DKind == OMPD_parallel_master_taskloop ||
+ isOpenMPDistributeDirective(DKind)) &&
+ !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
+ DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) &&
+ (DVar.CKind != OMPC_private || DVar.RefExpr)) {
+ Diag(Init->getBeginLoc(), diag::err_omp_loop_var_dsa)
+ << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPDirectiveName(DKind)
+ << getOpenMPClauseName(PredeterminedCKind);
+ if (DVar.RefExpr == nullptr)
+ DVar.CKind = PredeterminedCKind;
+ reportOriginalDsa(*this, DSAStack, D, DVar,
+ /*IsLoopIterVar=*/true);
+ } else if (LoopDeclRefExpr) {
+ // Make the loop iteration variable private (for worksharing
+ // constructs), linear (for simd directives with the only one
+ // associated loop) or lastprivate (for simd directives with several
+ // collapsed or ordered loops).
+ if (DVar.CKind == OMPC_unknown)
+ DSAStack->addDSA(D, LoopDeclRefExpr, PredeterminedCKind,
+ PrivateRef);
+ }
}
}
DSAStack->setAssociatedLoops(AssociatedLoops - 1);
@@ -5637,12 +6548,15 @@ static bool checkOpenMPIterationSpace(
unsigned TotalNestedLoopCount, Expr *CollapseLoopCountExpr,
Expr *OrderedLoopCountExpr,
Sema::VarsWithInheritedDSAType &VarsWithImplicitDSA,
- LoopIterationSpace &ResultIterSpace,
+ llvm::MutableArrayRef<LoopIterationSpace> ResultIterSpaces,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
- // OpenMP [2.6, Canonical Loop Form]
+ // OpenMP [2.9.1, Canonical Loop Form]
// for (init-expr; test-expr; incr-expr) structured-block
+ // for (range-decl: range-expr) structured-block
auto *For = dyn_cast_or_null<ForStmt>(S);
- if (!For) {
+ auto *CXXFor = dyn_cast_or_null<CXXForRangeStmt>(S);
+ // Ranged for is supported only in OpenMP 5.0.
+ if (!For && (SemaRef.LangOpts.OpenMP <= 45 || !CXXFor)) {
SemaRef.Diag(S->getBeginLoc(), diag::err_omp_not_for)
<< (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr)
<< getOpenMPDirectiveName(DKind) << TotalNestedLoopCount
@@ -5664,12 +6578,14 @@ static bool checkOpenMPIterationSpace(
}
return true;
}
- assert(For->getBody());
+ assert(((For && For->getBody()) || (CXXFor && CXXFor->getBody())) &&
+ "No loop body.");
- OpenMPIterationSpaceChecker ISC(SemaRef, DSA, For->getForLoc());
+ OpenMPIterationSpaceChecker ISC(SemaRef, DSA,
+ For ? For->getForLoc() : CXXFor->getForLoc());
// Check init.
- Stmt *Init = For->getInit();
+ Stmt *Init = For ? For->getInit() : CXXFor->getBeginStmt();
if (ISC.checkAndSetInit(Init))
return true;
@@ -5677,8 +6593,6 @@ static bool checkOpenMPIterationSpace(
// Check loop variable's type.
if (ValueDecl *LCDecl = ISC.getLoopDecl()) {
- Expr *LoopDeclRefExpr = ISC.getLoopDeclRefExpr();
-
// OpenMP [2.6, Canonical Loop Form]
// Var is one of the following:
// A variable of signed or unsigned integer type.
@@ -5704,90 +6618,70 @@ static bool checkOpenMPIterationSpace(
// sharing attributes.
VarsWithImplicitDSA.erase(LCDecl);
- // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
- // in a Construct, C/C++].
- // The loop iteration variable in the associated for-loop of a simd
- // construct with just one associated for-loop may be listed in a linear
- // clause with a constant-linear-step that is the increment of the
- // associated for-loop.
- // The loop iteration variable(s) in the associated for-loop(s) of a for or
- // parallel for construct may be listed in a private or lastprivate clause.
- DSAStackTy::DSAVarData DVar = DSA.getTopDSA(LCDecl, false);
- // If LoopVarRefExpr is nullptr it means the corresponding loop variable is
- // declared in the loop and it is predetermined as a private.
- OpenMPClauseKind PredeterminedCKind =
- isOpenMPSimdDirective(DKind)
- ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate)
- : OMPC_private;
- if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
- DVar.CKind != PredeterminedCKind && DVar.RefExpr &&
- (SemaRef.getLangOpts().OpenMP <= 45 ||
- (DVar.CKind != OMPC_lastprivate && DVar.CKind != OMPC_private))) ||
- ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop ||
- isOpenMPDistributeDirective(DKind)) &&
- !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
- DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) &&
- (DVar.CKind != OMPC_private || DVar.RefExpr)) {
- SemaRef.Diag(Init->getBeginLoc(), diag::err_omp_loop_var_dsa)
- << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind)
- << getOpenMPClauseName(PredeterminedCKind);
- if (DVar.RefExpr == nullptr)
- DVar.CKind = PredeterminedCKind;
- reportOriginalDsa(SemaRef, &DSA, LCDecl, DVar, /*IsLoopIterVar=*/true);
- HasErrors = true;
- } else if (LoopDeclRefExpr != nullptr) {
- // Make the loop iteration variable private (for worksharing constructs),
- // linear (for simd directives with the only one associated loop) or
- // lastprivate (for simd directives with several collapsed or ordered
- // loops).
- if (DVar.CKind == OMPC_unknown)
- DSA.addDSA(LCDecl, LoopDeclRefExpr, PredeterminedCKind);
- }
-
assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars");
// Check test-expr.
- HasErrors |= ISC.checkAndSetCond(For->getCond());
+ HasErrors |= ISC.checkAndSetCond(For ? For->getCond() : CXXFor->getCond());
// Check incr-expr.
- HasErrors |= ISC.checkAndSetInc(For->getInc());
+ HasErrors |= ISC.checkAndSetInc(For ? For->getInc() : CXXFor->getInc());
}
if (ISC.dependent() || SemaRef.CurContext->isDependentContext() || HasErrors)
return HasErrors;
// Build the loop's iteration space representation.
- ResultIterSpace.PreCond =
- ISC.buildPreCond(DSA.getCurScope(), For->getCond(), Captures);
- ResultIterSpace.NumIterations = ISC.buildNumIterations(
- DSA.getCurScope(),
- (isOpenMPWorksharingDirective(DKind) ||
- isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)),
- Captures);
- ResultIterSpace.CounterVar = ISC.buildCounterVar(Captures, DSA);
- ResultIterSpace.PrivateCounterVar = ISC.buildPrivateCounterVar();
- ResultIterSpace.CounterInit = ISC.buildCounterInit();
- ResultIterSpace.CounterStep = ISC.buildCounterStep();
- ResultIterSpace.InitSrcRange = ISC.getInitSrcRange();
- ResultIterSpace.CondSrcRange = ISC.getConditionSrcRange();
- ResultIterSpace.IncSrcRange = ISC.getIncrementSrcRange();
- ResultIterSpace.Subtract = ISC.shouldSubtractStep();
- ResultIterSpace.IsStrictCompare = ISC.isStrictTestOp();
-
- HasErrors |= (ResultIterSpace.PreCond == nullptr ||
- ResultIterSpace.NumIterations == nullptr ||
- ResultIterSpace.CounterVar == nullptr ||
- ResultIterSpace.PrivateCounterVar == nullptr ||
- ResultIterSpace.CounterInit == nullptr ||
- ResultIterSpace.CounterStep == nullptr);
+ ResultIterSpaces[CurrentNestedLoopCount].PreCond = ISC.buildPreCond(
+ DSA.getCurScope(), For ? For->getCond() : CXXFor->getCond(), Captures);
+ ResultIterSpaces[CurrentNestedLoopCount].NumIterations =
+ ISC.buildNumIterations(DSA.getCurScope(), ResultIterSpaces,
+ (isOpenMPWorksharingDirective(DKind) ||
+ isOpenMPTaskLoopDirective(DKind) ||
+ isOpenMPDistributeDirective(DKind)),
+ Captures);
+ ResultIterSpaces[CurrentNestedLoopCount].CounterVar =
+ ISC.buildCounterVar(Captures, DSA);
+ ResultIterSpaces[CurrentNestedLoopCount].PrivateCounterVar =
+ ISC.buildPrivateCounterVar();
+ ResultIterSpaces[CurrentNestedLoopCount].CounterInit = ISC.buildCounterInit();
+ ResultIterSpaces[CurrentNestedLoopCount].CounterStep = ISC.buildCounterStep();
+ ResultIterSpaces[CurrentNestedLoopCount].InitSrcRange = ISC.getInitSrcRange();
+ ResultIterSpaces[CurrentNestedLoopCount].CondSrcRange =
+ ISC.getConditionSrcRange();
+ ResultIterSpaces[CurrentNestedLoopCount].IncSrcRange =
+ ISC.getIncrementSrcRange();
+ ResultIterSpaces[CurrentNestedLoopCount].Subtract = ISC.shouldSubtractStep();
+ ResultIterSpaces[CurrentNestedLoopCount].IsStrictCompare =
+ ISC.isStrictTestOp();
+ std::tie(ResultIterSpaces[CurrentNestedLoopCount].MinValue,
+ ResultIterSpaces[CurrentNestedLoopCount].MaxValue) =
+ ISC.buildMinMaxValues(DSA.getCurScope(), Captures);
+ ResultIterSpaces[CurrentNestedLoopCount].FinalCondition =
+ ISC.buildFinalCondition(DSA.getCurScope());
+ ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularLB =
+ ISC.doesInitDependOnLC();
+ ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularUB =
+ ISC.doesCondDependOnLC();
+ ResultIterSpaces[CurrentNestedLoopCount].LoopDependentIdx =
+ ISC.getLoopDependentIdx();
+
+ HasErrors |=
+ (ResultIterSpaces[CurrentNestedLoopCount].PreCond == nullptr ||
+ ResultIterSpaces[CurrentNestedLoopCount].NumIterations == nullptr ||
+ ResultIterSpaces[CurrentNestedLoopCount].CounterVar == nullptr ||
+ ResultIterSpaces[CurrentNestedLoopCount].PrivateCounterVar == nullptr ||
+ ResultIterSpaces[CurrentNestedLoopCount].CounterInit == nullptr ||
+ ResultIterSpaces[CurrentNestedLoopCount].CounterStep == nullptr);
if (!HasErrors && DSA.isOrderedRegion()) {
if (DSA.getOrderedRegionParam().second->getNumForLoops()) {
if (CurrentNestedLoopCount <
DSA.getOrderedRegionParam().second->getLoopNumIterations().size()) {
DSA.getOrderedRegionParam().second->setLoopNumIterations(
- CurrentNestedLoopCount, ResultIterSpace.NumIterations);
+ CurrentNestedLoopCount,
+ ResultIterSpaces[CurrentNestedLoopCount].NumIterations);
DSA.getOrderedRegionParam().second->setLoopCounter(
- CurrentNestedLoopCount, ResultIterSpace.CounterVar);
+ CurrentNestedLoopCount,
+ ResultIterSpaces[CurrentNestedLoopCount].CounterVar);
}
}
for (auto &Pair : DSA.getDoacrossDependClauses()) {
@@ -5804,11 +6698,13 @@ static bool checkOpenMPIterationSpace(
Expr *CntValue;
if (Pair.first->getDependencyKind() == OMPC_DEPEND_source)
CntValue = ISC.buildOrderedLoopData(
- DSA.getCurScope(), ResultIterSpace.CounterVar, Captures,
+ DSA.getCurScope(),
+ ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures,
Pair.first->getDependencyLoc());
else
CntValue = ISC.buildOrderedLoopData(
- DSA.getCurScope(), ResultIterSpace.CounterVar, Captures,
+ DSA.getCurScope(),
+ ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures,
Pair.first->getDependencyLoc(),
Pair.second[CurrentNestedLoopCount].first,
Pair.second[CurrentNestedLoopCount].second);
@@ -5822,10 +6718,12 @@ static bool checkOpenMPIterationSpace(
/// Build 'VarRef = Start.
static ExprResult
buildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef,
- ExprResult Start,
+ ExprResult Start, bool IsNonRectangularLB,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
// Build 'VarRef = Start.
- ExprResult NewStart = tryBuildCapture(SemaRef, Start.get(), Captures);
+ ExprResult NewStart = IsNonRectangularLB
+ ? Start.get()
+ : tryBuildCapture(SemaRef, Start.get(), Captures);
if (!NewStart.isUsable())
return ExprError();
if (!SemaRef.Context.hasSameType(NewStart.get()->getType(),
@@ -5846,6 +6744,7 @@ buildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef,
static ExprResult buildCounterUpdate(
Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef,
ExprResult Start, ExprResult Iter, ExprResult Step, bool Subtract,
+ bool IsNonRectangularLB,
llvm::MapVector<const Expr *, DeclRefExpr *> *Captures = nullptr) {
// Add parentheses (for debugging purposes only).
Iter = SemaRef.ActOnParenExpr(Loc, Loc, Iter.get());
@@ -5865,8 +6764,12 @@ static ExprResult buildCounterUpdate(
// Try to build 'VarRef = Start, VarRef (+|-)= Iter * Step' or
// 'VarRef = Start (+|-) Iter * Step'.
- ExprResult NewStart = Start;
- if (Captures)
+ if (!Start.isUsable())
+ return ExprError();
+ ExprResult NewStart = SemaRef.ActOnParenExpr(Loc, Loc, Start.get());
+ if (!NewStart.isUsable())
+ return ExprError();
+ if (Captures && !IsNonRectangularLB)
NewStart = tryBuildCapture(SemaRef, Start.get(), *Captures);
if (NewStart.isInvalid())
return ExprError();
@@ -5877,8 +6780,8 @@ static ExprResult buildCounterUpdate(
if (VarRef.get()->getType()->isOverloadableType() ||
NewStart.get()->getType()->isOverloadableType() ||
Update.get()->getType()->isOverloadableType()) {
- bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics();
- SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true);
+ Sema::TentativeAnalysisScope Trap(SemaRef);
+
Update =
SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), NewStart.get());
if (Update.isUsable()) {
@@ -5890,7 +6793,6 @@ static ExprResult buildCounterUpdate(
UpdateVal.get());
}
}
- SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress);
}
// Second attempt: try to build 'VarRef = Start (+|-) Iter * Step'.
@@ -6037,22 +6939,27 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
if (checkOpenMPIterationSpace(
DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount,
std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr,
- OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces[Cnt],
- Captures))
+ OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces, Captures))
return 0;
// Move on to the next nested for loop, or to the loop body.
// OpenMP [2.8.1, simd construct, Restrictions]
// All loops associated with the construct must be perfectly nested; that
// is, there must be no intervening code nor any OpenMP directive between
// any two loops.
- CurStmt = cast<ForStmt>(CurStmt)->getBody()->IgnoreContainers();
+ if (auto *For = dyn_cast<ForStmt>(CurStmt)) {
+ CurStmt = For->getBody();
+ } else {
+ assert(isa<CXXForRangeStmt>(CurStmt) &&
+ "Expected canonical for or range-based for loops.");
+ CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody();
+ }
+ CurStmt = CurStmt->IgnoreContainers();
}
for (unsigned Cnt = NestedLoopCount; Cnt < OrderedLoopCount; ++Cnt) {
if (checkOpenMPIterationSpace(
DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount,
std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr,
- OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces[Cnt],
- Captures))
+ OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces, Captures))
return 0;
if (Cnt > 0 && IterSpaces[Cnt].CounterVar) {
// Handle initialization of captured loop iterator variables.
@@ -6066,7 +6973,14 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
// All loops associated with the construct must be perfectly nested; that
// is, there must be no intervening code nor any OpenMP directive between
// any two loops.
- CurStmt = cast<ForStmt>(CurStmt)->getBody()->IgnoreContainers();
+ if (auto *For = dyn_cast<ForStmt>(CurStmt)) {
+ CurStmt = For->getBody();
+ } else {
+ assert(isa<CXXForRangeStmt>(CurStmt) &&
+ "Expected canonical for or range-based for loops.");
+ CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody();
+ }
+ CurStmt = CurStmt->IgnoreContainers();
}
Built.clear(/* size */ NestedLoopCount);
@@ -6513,6 +7427,9 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Built.Inits.resize(NestedLoopCount);
Built.Updates.resize(NestedLoopCount);
Built.Finals.resize(NestedLoopCount);
+ Built.DependentCounters.resize(NestedLoopCount);
+ Built.DependentInits.resize(NestedLoopCount);
+ Built.FinalsConditions.resize(NestedLoopCount);
{
// We implement the following algorithm for obtaining the
// original loop iteration variable values based on the
@@ -6572,24 +7489,26 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
DeclRefExpr *CounterVar = buildDeclRefExpr(
SemaRef, VD, IS.CounterVar->getType(), IS.CounterVar->getExprLoc(),
/*RefersToCapture=*/true);
- ExprResult Init = buildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar,
- IS.CounterInit, Captures);
+ ExprResult Init =
+ buildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar,
+ IS.CounterInit, IS.IsNonRectangularLB, Captures);
if (!Init.isUsable()) {
HasErrors = true;
break;
}
ExprResult Update = buildCounterUpdate(
SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, Iter,
- IS.CounterStep, IS.Subtract, &Captures);
+ IS.CounterStep, IS.Subtract, IS.IsNonRectangularLB, &Captures);
if (!Update.isUsable()) {
HasErrors = true;
break;
}
// Build final: IS.CounterVar = IS.Start + IS.NumIters * IS.Step
- ExprResult Final = buildCounterUpdate(
- SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit,
- IS.NumIterations, IS.CounterStep, IS.Subtract, &Captures);
+ ExprResult Final =
+ buildCounterUpdate(SemaRef, CurScope, UpdLoc, CounterVar,
+ IS.CounterInit, IS.NumIterations, IS.CounterStep,
+ IS.Subtract, IS.IsNonRectangularLB, &Captures);
if (!Final.isUsable()) {
HasErrors = true;
break;
@@ -6605,6 +7524,16 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Built.Inits[Cnt] = Init.get();
Built.Updates[Cnt] = Update.get();
Built.Finals[Cnt] = Final.get();
+ Built.DependentCounters[Cnt] = nullptr;
+ Built.DependentInits[Cnt] = nullptr;
+ Built.FinalsConditions[Cnt] = nullptr;
+ if (IS.IsNonRectangularLB || IS.IsNonRectangularUB) {
+ Built.DependentCounters[Cnt] =
+ Built.Counters[NestedLoopCount - 1 - IS.LoopDependentIdx];
+ Built.DependentInits[Cnt] =
+ Built.Inits[NestedLoopCount - 1 - IS.LoopDependentIdx];
+ Built.FinalsConditions[Cnt] = IS.FinalCondition;
+ }
}
}
@@ -6617,7 +7546,7 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Built.NumIterations = NumIterations.get();
Built.CalcLastIteration = SemaRef
.ActOnFinishFullExpr(CalcLastIteration.get(),
- /*DiscardedValue*/ false)
+ /*DiscardedValue=*/false)
.get();
Built.PreCond = PreCond.get();
Built.PreInits = buildPreInits(C, Captures);
@@ -8398,6 +9327,146 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective(
NestedLoopCount, Clauses, AStmt, B);
}
+StmtResult Sema::ActOnOpenMPMasterTaskLoopDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount =
+ checkOpenMPLoop(OMPD_master_taskloop, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // The grainsize clause and num_tasks clause are mutually exclusive and may
+ // not appear on the same taskloop directive.
+ if (checkGrainsizeNumTasksClauses(*this, Clauses))
+ return StmtError();
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // If a reduction clause is present on the taskloop directive, the nogroup
+ // clause must not be specified.
+ if (checkReductionClauseWithNogroup(*this, Clauses))
+ return StmtError();
+
+ setFunctionHasBranchProtectedScope();
+ return OMPMasterTaskLoopDirective::Create(Context, StartLoc, EndLoc,
+ NestedLoopCount, Clauses, AStmt, B);
+}
+
+StmtResult Sema::ActOnOpenMPMasterTaskLoopSimdDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount =
+ checkOpenMPLoop(OMPD_master_taskloop_simd, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ if (!CurContext->isDependentContext()) {
+ // Finalize the clauses that need pre-built expressions for CodeGen.
+ for (OMPClause *C : Clauses) {
+ if (auto *LC = dyn_cast<OMPLinearClause>(C))
+ if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
+ B.NumIterations, *this, CurScope,
+ DSAStack))
+ return StmtError();
+ }
+ }
+
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // The grainsize clause and num_tasks clause are mutually exclusive and may
+ // not appear on the same taskloop directive.
+ if (checkGrainsizeNumTasksClauses(*this, Clauses))
+ return StmtError();
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // If a reduction clause is present on the taskloop directive, the nogroup
+ // clause must not be specified.
+ if (checkReductionClauseWithNogroup(*this, Clauses))
+ return StmtError();
+ if (checkSimdlenSafelenSpecified(*this, Clauses))
+ return StmtError();
+
+ setFunctionHasBranchProtectedScope();
+ return OMPMasterTaskLoopSimdDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+}
+
+StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ auto *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel =
+ getOpenMPCaptureLevels(OMPD_parallel_master_taskloop);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
+
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount = checkOpenMPLoop(
+ OMPD_parallel_master_taskloop, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, CS, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // The grainsize clause and num_tasks clause are mutually exclusive and may
+ // not appear on the same taskloop directive.
+ if (checkGrainsizeNumTasksClauses(*this, Clauses))
+ return StmtError();
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // If a reduction clause is present on the taskloop directive, the nogroup
+ // clause must not be specified.
+ if (checkReductionClauseWithNogroup(*this, Clauses))
+ return StmtError();
+
+ setFunctionHasBranchProtectedScope();
+ return OMPParallelMasterTaskLoopDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+}
+
StmtResult Sema::ActOnOpenMPDistributeDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
@@ -9246,6 +10315,8 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -9287,6 +10358,10 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_exit_data:
CaptureRegion = OMPD_task;
break;
+ case OMPD_parallel_master_taskloop:
+ if (NameModifier == OMPD_unknown || NameModifier == OMPD_taskloop)
+ CaptureRegion = OMPD_parallel;
+ break;
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_sections:
@@ -9302,6 +10377,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
case OMPD_target_data:
// Do not capture if-clause expressions.
break;
@@ -9315,6 +10392,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_teams:
@@ -9358,6 +10436,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_parallel_for_simd:
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
+ case OMPD_parallel_master_taskloop:
// Do not capture num_threads-clause expressions.
break;
case OMPD_target_data:
@@ -9373,6 +10452,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
@@ -9383,6 +10464,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_teams:
@@ -9428,6 +10510,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -9452,6 +10537,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -9494,6 +10580,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -9518,6 +10607,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -9560,6 +10650,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -9585,6 +10678,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -9630,6 +10724,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -9651,6 +10748,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -9701,6 +10799,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_sections:
@@ -9716,6 +10817,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -9737,6 +10839,78 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
llvm_unreachable("Unknown OpenMP directive");
}
break;
+ case OMPC_grainsize:
+ case OMPC_num_tasks:
+ case OMPC_final:
+ case OMPC_priority:
+ switch (DKind) {
+ case OMPD_task:
+ case OMPD_taskloop:
+ case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ break;
+ case OMPD_parallel_master_taskloop:
+ CaptureRegion = OMPD_parallel;
+ break;
+ case OMPD_target_update:
+ case OMPD_target_enter_data:
+ case OMPD_target_exit_data:
+ case OMPD_target:
+ case OMPD_target_simd:
+ case OMPD_target_teams:
+ case OMPD_target_parallel:
+ case OMPD_target_teams_distribute:
+ case OMPD_target_teams_distribute_simd:
+ case OMPD_target_parallel_for:
+ case OMPD_target_parallel_for_simd:
+ case OMPD_target_teams_distribute_parallel_for:
+ case OMPD_target_teams_distribute_parallel_for_simd:
+ case OMPD_target_data:
+ case OMPD_teams_distribute_parallel_for:
+ case OMPD_teams_distribute_parallel_for_simd:
+ case OMPD_teams:
+ case OMPD_teams_distribute:
+ case OMPD_teams_distribute_simd:
+ case OMPD_distribute_parallel_for:
+ case OMPD_distribute_parallel_for_simd:
+ case OMPD_cancel:
+ case OMPD_parallel:
+ case OMPD_parallel_sections:
+ case OMPD_parallel_for:
+ case OMPD_parallel_for_simd:
+ case OMPD_threadprivate:
+ case OMPD_allocate:
+ case OMPD_taskyield:
+ case OMPD_barrier:
+ case OMPD_taskwait:
+ case OMPD_cancellation_point:
+ case OMPD_flush:
+ case OMPD_declare_reduction:
+ case OMPD_declare_mapper:
+ case OMPD_declare_simd:
+ case OMPD_declare_variant:
+ case OMPD_declare_target:
+ case OMPD_end_declare_target:
+ case OMPD_simd:
+ case OMPD_for:
+ case OMPD_for_simd:
+ case OMPD_sections:
+ case OMPD_section:
+ case OMPD_single:
+ case OMPD_master:
+ case OMPD_critical:
+ case OMPD_taskgroup:
+ case OMPD_distribute:
+ case OMPD_ordered:
+ case OMPD_atomic:
+ case OMPD_distribute_simd:
+ case OMPD_requires:
+ llvm_unreachable("Unexpected OpenMP directive with grainsize-clause");
+ case OMPD_unknown:
+ llvm_unreachable("Unknown OpenMP directive");
+ }
+ break;
case OMPC_firstprivate:
case OMPC_lastprivate:
case OMPC_reduction:
@@ -9745,7 +10919,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_linear:
case OMPC_default:
case OMPC_proc_bind:
- case OMPC_final:
case OMPC_safelen:
case OMPC_simdlen:
case OMPC_allocator:
@@ -9771,10 +10944,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_threads:
case OMPC_simd:
case OMPC_map:
- case OMPC_priority:
- case OMPC_grainsize:
case OMPC_nogroup:
- case OMPC_num_tasks:
case OMPC_hint:
case OMPC_defaultmap:
case OMPC_unknown:
@@ -9788,6 +10958,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Unexpected OpenMP clause.");
}
return CaptureRegion;
@@ -9832,6 +11004,8 @@ OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = Condition;
+ Stmt *HelperValStmt = nullptr;
+ OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
if (!Condition->isValueDependent() && !Condition->isTypeDependent() &&
!Condition->isInstantiationDependent() &&
!Condition->containsUnexpandedParameterPack()) {
@@ -9840,10 +11014,21 @@ OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition,
return nullptr;
ValExpr = MakeFullExpr(Val.get()).get();
+
+ OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
+ CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_final);
+ if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
+ ValExpr = MakeFullExpr(ValExpr).get();
+ llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
+ ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
+ HelperValStmt = buildPreInits(Context, Captures);
+ }
}
- return new (Context) OMPFinalClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+ return new (Context) OMPFinalClause(ValExpr, HelperValStmt, CaptureRegion,
+ StartLoc, LParenLoc, EndLoc);
}
+
ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc,
Expr *Op) {
if (!Op)
@@ -9888,9 +11073,12 @@ ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc,
return PerformContextualImplicitConversion(Loc, Op, ConvertDiagnoser);
}
-static bool isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef,
- OpenMPClauseKind CKind,
- bool StrictlyPositive) {
+static bool
+isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, OpenMPClauseKind CKind,
+ bool StrictlyPositive, bool BuildCapture = false,
+ OpenMPDirectiveKind DKind = OMPD_unknown,
+ OpenMPDirectiveKind *CaptureRegion = nullptr,
+ Stmt **HelperValStmt = nullptr) {
if (!ValExpr->isTypeDependent() && !ValExpr->isValueDependent() &&
!ValExpr->isInstantiationDependent()) {
SourceLocation Loc = ValExpr->getExprLoc();
@@ -9911,6 +11099,16 @@ static bool isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef,
<< ValExpr->getSourceRange();
return false;
}
+ if (!BuildCapture)
+ return true;
+ *CaptureRegion = getOpenMPCaptureRegionForClause(DKind, CKind);
+ if (*CaptureRegion != OMPD_unknown &&
+ !SemaRef.CurContext->isDependentContext()) {
+ ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
+ llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
+ ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get();
+ *HelperValStmt = buildPreInits(SemaRef.Context, Captures);
+ }
}
return true;
}
@@ -10181,6 +11379,8 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_unified_shared_memory:
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -10359,6 +11559,8 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -10568,6 +11770,8 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_use_device_ptr:
case OMPC_is_device_ptr:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -10774,6 +11978,8 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -10874,7 +12080,13 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
// OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
// A list item cannot appear in both a map clause and a data-sharing
// attribute clause on the same construct
- if (isOpenMPTargetExecutionDirective(CurrDir)) {
+ //
+ // OpenMP 5.0 [2.19.7.1, Restrictions, p.7]
+ // A list item cannot appear in both a map clause and a data-sharing
+ // attribute clause on the same construct unless the construct is a
+ // combined construct.
+ if ((LangOpts.OpenMP <= 45 && isOpenMPTargetExecutionDirective(CurrDir)) ||
+ CurrDir == OMPD_target) {
OpenMPClauseKind ConflictKind;
if (DSAStack->checkMappableExprComponentListsForDecl(
VD, /*CurrentRegionOnly=*/true,
@@ -11109,7 +12321,14 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
// OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
// A list item cannot appear in both a map clause and a data-sharing
// attribute clause on the same construct
- if (isOpenMPTargetExecutionDirective(CurrDir)) {
+ //
+ // OpenMP 5.0 [2.19.7.1, Restrictions, p.7]
+ // A list item cannot appear in both a map clause and a data-sharing
+ // attribute clause on the same construct unless the construct is a
+ // combined construct.
+ if ((LangOpts.OpenMP <= 45 &&
+ isOpenMPTargetExecutionDirective(CurrDir)) ||
+ CurrDir == OMPD_target) {
OpenMPClauseKind ConflictKind;
if (DSAStack->checkMappableExprComponentListsForDecl(
VD, /*CurrentRegionOnly=*/true,
@@ -12133,8 +13352,9 @@ static bool actOnOMPReductionKindClause(
// If we don't have a single element, we must emit a constant array type.
if (ConstantLengthOASE && !SingleElement) {
for (llvm::APSInt &Size : ArraySizes)
- PrivateTy = Context.getConstantArrayType(
- PrivateTy, Size, ArrayType::Normal, /*IndexTypeQuals=*/0);
+ PrivateTy = Context.getConstantArrayType(PrivateTy, Size, nullptr,
+ ArrayType::Normal,
+ /*IndexTypeQuals=*/0);
}
}
@@ -12707,6 +13927,7 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
// Walk the vars and build update/final expressions for the CodeGen.
SmallVector<Expr *, 8> Updates;
SmallVector<Expr *, 8> Finals;
+ SmallVector<Expr *, 8> UsedExprs;
Expr *Step = Clause.getStep();
Expr *CalcStep = Clause.getCalcStep();
// OpenMP [2.14.3.7, linear clause]
@@ -12760,9 +13981,9 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
// Build update: Var = InitExpr + IV * Step
ExprResult Update;
if (!Info.first)
- Update =
- buildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate,
- InitExpr, IV, Step, /* Subtract */ false);
+ Update = buildCounterUpdate(
+ SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, InitExpr, IV, Step,
+ /*Subtract=*/false, /*IsNonRectangularLB=*/false);
else
Update = *CurPrivate;
Update = SemaRef.ActOnFinishFullExpr(Update.get(), DE->getBeginLoc(),
@@ -12773,7 +13994,8 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
if (!Info.first)
Final =
buildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef,
- InitExpr, NumIterations, Step, /*Subtract=*/false);
+ InitExpr, NumIterations, Step, /*Subtract=*/false,
+ /*IsNonRectangularLB=*/false);
else
Final = *CurPrivate;
Final = SemaRef.ActOnFinishFullExpr(Final.get(), DE->getBeginLoc(),
@@ -12782,16 +14004,24 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
if (!Update.isUsable() || !Final.isUsable()) {
Updates.push_back(nullptr);
Finals.push_back(nullptr);
+ UsedExprs.push_back(nullptr);
HasErrors = true;
} else {
Updates.push_back(Update.get());
Finals.push_back(Final.get());
+ if (!Info.first)
+ UsedExprs.push_back(SimpleRefExpr);
}
++CurInit;
++CurPrivate;
}
+ if (Expr *S = Clause.getStep())
+ UsedExprs.push_back(S);
+ // Fill the remaining part with the nullptr.
+ UsedExprs.append(Clause.varlist_size() + 1 - UsedExprs.size(), nullptr);
Clause.setUpdates(Updates);
Clause.setFinals(Finals);
+ Clause.setUsedExprs(UsedExprs);
return HasErrors;
}
@@ -13216,11 +14446,13 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
<< RefExpr->getSourceRange();
continue;
}
- bool Suppress = getDiagnostics().getSuppressAllDiagnostics();
- getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true);
- ExprResult Res =
- CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RefExpr->IgnoreParenImpCasts());
- getDiagnostics().setSuppressAllDiagnostics(Suppress);
+
+ ExprResult Res;
+ {
+ Sema::TentativeAnalysisScope Trap(*this);
+ Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf,
+ RefExpr->IgnoreParenImpCasts());
+ }
if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr)) {
Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
<< RefExpr->getSourceRange();
@@ -13884,6 +15116,11 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
Expr *UnresolvedMapper) {
if (MapperIdScopeSpec.isInvalid())
return ExprError();
+ // Get the actual type for the array type.
+ if (Type->isArrayType()) {
+ assert(Type->getAsArrayTypeUnsafe() && "Expect to get a valid array type");
+ Type = Type->getAsArrayTypeUnsafe()->getElementType().getCanonicalType();
+ }
// Find all user-defined mappers with the given MapperId.
SmallVector<UnresolvedSet<8>, 4> Lookups;
LookupResult Lookup(SemaRef, MapperId, Sema::LookupOMPMapperName);
@@ -13930,11 +15167,14 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
MapperIdScopeSpec.getWithLocInContext(SemaRef.Context), MapperId,
/*ADL=*/false, /*Overloaded=*/true, URS.begin(), URS.end());
}
+ SourceLocation Loc = MapperId.getLoc();
// [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions
// The type must be of struct, union or class type in C and C++
- if (!Type->isStructureOrClassType() && !Type->isUnionType())
- return ExprEmpty();
- SourceLocation Loc = MapperId.getLoc();
+ if (!Type->isStructureOrClassType() && !Type->isUnionType() &&
+ (MapperIdScopeSpec.isSet() || MapperId.getAsString() != "default")) {
+ SemaRef.Diag(Loc, diag::err_omp_mapper_wrong_type);
+ return ExprError();
+ }
// Perform argument dependent lookup.
if (SemaRef.getLangOpts().CPlusPlus && !MapperIdScopeSpec.isSet())
argumentDependentLookup(SemaRef, MapperId, Loc, Type, Lookups);
@@ -14211,7 +15451,14 @@ static void checkMappableExpressionList(
// OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
// A list item cannot appear in both a map clause and a data-sharing
// attribute clause on the same construct
- if (VD && isOpenMPTargetExecutionDirective(DKind)) {
+ //
+ // OpenMP 5.0 [2.19.7.1, Restrictions, p.7]
+ // A list item cannot appear in both a map clause and a data-sharing
+ // attribute clause on the same construct unless the construct is a
+ // combined construct.
+ if (VD && ((SemaRef.LangOpts.OpenMP <= 45 &&
+ isOpenMPTargetExecutionDirective(DKind)) ||
+ DKind == OMPD_target)) {
DSAStackTy::DSAVarData DVar = DSAS->getTopDSA(VD, /*FromParent=*/false);
if (isOpenMPPrivate(DVar.CKind)) {
SemaRef.Diag(ELoc, diag::err_omp_variable_in_given_clause_and_dsa)
@@ -14745,14 +15992,19 @@ OMPClause *Sema::ActOnOpenMPPriorityClause(Expr *Priority,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = Priority;
+ Stmt *HelperValStmt = nullptr;
+ OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
// OpenMP [2.9.1, task Constrcut]
// The priority-value is a non-negative numerical scalar expression.
- if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_priority,
- /*StrictlyPositive=*/false))
+ if (!isNonNegativeIntegerValue(
+ ValExpr, *this, OMPC_priority,
+ /*StrictlyPositive=*/false, /*BuildCapture=*/true,
+ DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt))
return nullptr;
- return new (Context) OMPPriorityClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+ return new (Context) OMPPriorityClause(ValExpr, HelperValStmt, CaptureRegion,
+ StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize,
@@ -14760,15 +16012,20 @@ OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = Grainsize;
+ Stmt *HelperValStmt = nullptr;
+ OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
// OpenMP [2.9.2, taskloop Constrcut]
// The parameter of the grainsize clause must be a positive integer
// expression.
- if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_grainsize,
- /*StrictlyPositive=*/true))
+ if (!isNonNegativeIntegerValue(
+ ValExpr, *this, OMPC_grainsize,
+ /*StrictlyPositive=*/true, /*BuildCapture=*/true,
+ DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt))
return nullptr;
- return new (Context) OMPGrainsizeClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+ return new (Context) OMPGrainsizeClause(ValExpr, HelperValStmt, CaptureRegion,
+ StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks,
@@ -14776,15 +16033,20 @@ OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = NumTasks;
+ Stmt *HelperValStmt = nullptr;
+ OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
// OpenMP [2.9.2, taskloop Constrcut]
// The parameter of the num_tasks clause must be a positive integer
// expression.
- if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_num_tasks,
- /*StrictlyPositive=*/true))
+ if (!isNonNegativeIntegerValue(
+ ValExpr, *this, OMPC_num_tasks,
+ /*StrictlyPositive=*/true, /*BuildCapture=*/true,
+ DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt))
return nullptr;
- return new (Context) OMPNumTasksClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+ return new (Context) OMPNumTasksClause(ValExpr, HelperValStmt, CaptureRegion,
+ StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc,
@@ -14905,16 +16167,15 @@ void Sema::ActOnFinishOpenMPDeclareTargetDirective() {
--DeclareTargetNestingLevel;
}
-void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope,
- CXXScopeSpec &ScopeSpec,
- const DeclarationNameInfo &Id,
- OMPDeclareTargetDeclAttr::MapTypeTy MT,
- NamedDeclSetType &SameDirectiveDecls) {
+NamedDecl *
+Sema::lookupOpenMPDeclareTargetName(Scope *CurScope, CXXScopeSpec &ScopeSpec,
+ const DeclarationNameInfo &Id,
+ NamedDeclSetType &SameDirectiveDecls) {
LookupResult Lookup(*this, Id, LookupOrdinaryName);
LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
if (Lookup.isAmbiguous())
- return;
+ return nullptr;
Lookup.suppressDiagnostics();
if (!Lookup.isSingleResult()) {
@@ -14925,33 +16186,56 @@ void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope,
diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest)
<< Id.getName());
checkDeclIsAllowedInOpenMPTarget(nullptr, Corrected.getCorrectionDecl());
- return;
+ return nullptr;
}
Diag(Id.getLoc(), diag::err_undeclared_var_use) << Id.getName();
- return;
+ return nullptr;
}
NamedDecl *ND = Lookup.getAsSingle<NamedDecl>();
- if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND) ||
- isa<FunctionTemplateDecl>(ND)) {
- if (!SameDirectiveDecls.insert(cast<NamedDecl>(ND->getCanonicalDecl())))
- Diag(Id.getLoc(), diag::err_omp_declare_target_multiple) << Id.getName();
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
- OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(
- cast<ValueDecl>(ND));
- if (!Res) {
- auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT);
- ND->addAttr(A);
- if (ASTMutationListener *ML = Context.getASTMutationListener())
- ML->DeclarationMarkedOpenMPDeclareTarget(ND, A);
- checkDeclIsAllowedInOpenMPTarget(nullptr, ND, Id.getLoc());
- } else if (*Res != MT) {
- Diag(Id.getLoc(), diag::err_omp_declare_target_to_and_link)
- << Id.getName();
- }
- } else {
+ if (!isa<VarDecl>(ND) && !isa<FunctionDecl>(ND) &&
+ !isa<FunctionTemplateDecl>(ND)) {
Diag(Id.getLoc(), diag::err_omp_invalid_target_decl) << Id.getName();
+ return nullptr;
+ }
+ if (!SameDirectiveDecls.insert(cast<NamedDecl>(ND->getCanonicalDecl())))
+ Diag(Id.getLoc(), diag::err_omp_declare_target_multiple) << Id.getName();
+ return ND;
+}
+
+void Sema::ActOnOpenMPDeclareTargetName(
+ NamedDecl *ND, SourceLocation Loc, OMPDeclareTargetDeclAttr::MapTypeTy MT,
+ OMPDeclareTargetDeclAttr::DevTypeTy DT) {
+ assert((isa<VarDecl>(ND) || isa<FunctionDecl>(ND) ||
+ isa<FunctionTemplateDecl>(ND)) &&
+ "Expected variable, function or function template.");
+
+ // Diagnose marking after use as it may lead to incorrect diagnosis and
+ // codegen.
+ if (LangOpts.OpenMP >= 50 &&
+ (ND->isUsed(/*CheckUsedAttr=*/false) || ND->isReferenced()))
+ Diag(Loc, diag::warn_omp_declare_target_after_first_use);
+
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(cast<ValueDecl>(ND));
+ if (DevTy.hasValue() && *DevTy != DT) {
+ Diag(Loc, diag::err_omp_device_type_mismatch)
+ << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(DT)
+ << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(*DevTy);
+ return;
+ }
+ Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
+ OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(cast<ValueDecl>(ND));
+ if (!Res) {
+ auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT, DT,
+ SourceRange(Loc, Loc));
+ ND->addAttr(A);
+ if (ASTMutationListener *ML = Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPDeclareTarget(ND, A);
+ checkDeclIsAllowedInOpenMPTarget(nullptr, ND, Loc);
+ } else if (*Res != MT) {
+ Diag(Loc, diag::err_omp_declare_target_to_and_link) << ND;
}
}
@@ -14960,7 +16244,28 @@ static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR,
if (!D || !isa<VarDecl>(D))
return;
auto *VD = cast<VarDecl>(D);
- if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
+ Optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapTy =
+ OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
+ if (SemaRef.LangOpts.OpenMP >= 50 &&
+ (SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true) ||
+ SemaRef.getCurBlock() || SemaRef.getCurCapturedRegion()) &&
+ VD->hasGlobalStorage()) {
+ llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapTy =
+ OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
+ if (!MapTy || *MapTy != OMPDeclareTargetDeclAttr::MT_To) {
+ // OpenMP 5.0, 2.12.7 declare target Directive, Restrictions
+ // If a lambda declaration and definition appears between a
+ // declare target directive and the matching end declare target
+ // directive, all variables that are captured by the lambda
+ // expression must also appear in a to clause.
+ SemaRef.Diag(VD->getLocation(),
+ diag::err_omp_lambda_capture_in_declare_target_not_to);
+ SemaRef.Diag(SL, diag::note_var_explicitly_captured_here)
+ << VD << 0 << SR;
+ return;
+ }
+ }
+ if (MapTy.hasValue())
return;
SemaRef.Diag(VD->getLocation(), diag::warn_omp_not_in_target_context);
SemaRef.Diag(SL, diag::note_used_here) << SR;
@@ -14969,7 +16274,7 @@ static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR,
static bool checkValueDeclInTarget(SourceLocation SL, SourceRange SR,
Sema &SemaRef, DSAStackTy *Stack,
ValueDecl *VD) {
- return VD->hasAttr<OMPDeclareTargetDeclAttr>() ||
+ return OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD) ||
checkTypeMappable(SL, SR, SemaRef, Stack, VD->getType(),
/*FullCheck=*/false);
}
@@ -14995,15 +16300,23 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
}
if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
D = FTD->getTemplatedDecl();
- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(FD);
- if (Res && *Res == OMPDeclareTargetDeclAttr::MT_Link) {
- assert(IdLoc.isValid() && "Source location is expected");
+ if (IdLoc.isValid() && Res && *Res == OMPDeclareTargetDeclAttr::MT_Link) {
Diag(IdLoc, diag::err_omp_function_in_link_clause);
Diag(FD->getLocation(), diag::note_defined_here) << FD;
return;
}
+ // Mark the function as must be emitted for the device.
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(FD);
+ if (LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid() &&
+ *DevTy != OMPDeclareTargetDeclAttr::DT_Host)
+ checkOpenMPDeviceFunction(IdLoc, FD, /*CheckForDelayedContext=*/false);
+ if (!LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid() &&
+ *DevTy != OMPDeclareTargetDeclAttr::DT_NoHost)
+ checkOpenMPHostFunction(IdLoc, FD, /*CheckCaller=*/false);
}
if (auto *VD = dyn_cast<ValueDecl>(D)) {
// Problem if any with var declared with incomplete type will be reported
@@ -15016,7 +16329,8 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
if (isa<VarDecl>(D) || isa<FunctionDecl>(D) ||
isa<FunctionTemplateDecl>(D)) {
auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(
- Context, OMPDeclareTargetDeclAttr::MT_To);
+ Context, OMPDeclareTargetDeclAttr::MT_To,
+ OMPDeclareTargetDeclAttr::DT_Any, SourceRange(IdLoc, IdLoc));
D->addAttr(A);
if (ASTMutationListener *ML = Context.getASTMutationListener())
ML->DeclarationMarkedOpenMPDeclareTarget(D, A);
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index f632a4d3bd1a..47c1e3cec0ea 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -257,8 +257,18 @@ isPointerConversionToVoidPointer(ASTContext& Context) const {
/// Skip any implicit casts which could be either part of a narrowing conversion
/// or after one in an implicit conversion.
-static const Expr *IgnoreNarrowingConversion(const Expr *Converted) {
- while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Converted)) {
+static const Expr *IgnoreNarrowingConversion(ASTContext &Ctx,
+ const Expr *Converted) {
+ // We can have cleanups wrapping the converted expression; these need to be
+ // preserved so that destructors run if necessary.
+ if (auto *EWC = dyn_cast<ExprWithCleanups>(Converted)) {
+ Expr *Inner =
+ const_cast<Expr *>(IgnoreNarrowingConversion(Ctx, EWC->getSubExpr()));
+ return ExprWithCleanups::Create(Ctx, Inner, EWC->cleanupsHaveSideEffects(),
+ EWC->getObjects());
+ }
+
+ while (auto *ICE = dyn_cast<ImplicitCastExpr>(Converted)) {
switch (ICE->getCastKind()) {
case CK_NoOp:
case CK_IntegralCast:
@@ -332,7 +342,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
if (IgnoreFloatToIntegralConversion)
return NK_Not_Narrowing;
llvm::APSInt IntConstantValue;
- const Expr *Initializer = IgnoreNarrowingConversion(Converted);
+ const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted);
assert(Initializer && "Unknown conversion expression");
// If it's value-dependent, we can't tell whether it's narrowing.
@@ -370,7 +380,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
if (FromType->isRealFloatingType() && ToType->isRealFloatingType() &&
Ctx.getFloatingTypeOrder(FromType, ToType) == 1) {
// FromType is larger than ToType.
- const Expr *Initializer = IgnoreNarrowingConversion(Converted);
+ const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted);
// If it's value-dependent, we can't tell whether it's narrowing.
if (Initializer->isValueDependent())
@@ -416,7 +426,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
(FromSigned && !ToSigned)) {
// Not all values of FromType can be represented in ToType.
llvm::APSInt InitializerValue;
- const Expr *Initializer = IgnoreNarrowingConversion(Converted);
+ const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted);
// If it's value-dependent, we can't tell whether it's narrowing.
if (Initializer->isValueDependent())
@@ -838,6 +848,25 @@ llvm::Optional<unsigned> DeductionFailureInfo::getCallArgIndex() {
}
}
+bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(
+ OverloadedOperatorKind Op) {
+ if (!AllowRewrittenCandidates)
+ return false;
+ return Op == OO_EqualEqual || Op == OO_Spaceship;
+}
+
+bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(
+ ASTContext &Ctx, const FunctionDecl *FD) {
+ if (!shouldAddReversed(FD->getDeclName().getCXXOverloadedOperator()))
+ return false;
+ // Don't bother adding a reversed candidate that can never be a better
+ // match than the non-reversed version.
+ return FD->getNumParams() != 2 ||
+ !Ctx.hasSameUnqualifiedType(FD->getParamDecl(0)->getType(),
+ FD->getParamDecl(1)->getType()) ||
+ FD->hasAttr<EnableIfAttr>();
+}
+
void OverloadCandidateSet::destroyCandidates() {
for (iterator i = begin(), e = end(); i != e; ++i) {
for (auto &C : i->Conversions)
@@ -1463,14 +1492,14 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType,
if (TyClass != CanFrom->getTypeClass()) return false;
if (TyClass != Type::FunctionProto && TyClass != Type::FunctionNoProto) {
if (TyClass == Type::Pointer) {
- CanTo = CanTo.getAs<PointerType>()->getPointeeType();
- CanFrom = CanFrom.getAs<PointerType>()->getPointeeType();
+ CanTo = CanTo.castAs<PointerType>()->getPointeeType();
+ CanFrom = CanFrom.castAs<PointerType>()->getPointeeType();
} else if (TyClass == Type::BlockPointer) {
- CanTo = CanTo.getAs<BlockPointerType>()->getPointeeType();
- CanFrom = CanFrom.getAs<BlockPointerType>()->getPointeeType();
+ CanTo = CanTo.castAs<BlockPointerType>()->getPointeeType();
+ CanFrom = CanFrom.castAs<BlockPointerType>()->getPointeeType();
} else if (TyClass == Type::MemberPointer) {
- auto ToMPT = CanTo.getAs<MemberPointerType>();
- auto FromMPT = CanFrom.getAs<MemberPointerType>();
+ auto ToMPT = CanTo.castAs<MemberPointerType>();
+ auto FromMPT = CanFrom.castAs<MemberPointerType>();
// A function pointer conversion cannot change the class of the function.
if (ToMPT->getClass() != FromMPT->getClass())
return false;
@@ -2273,7 +2302,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
// Blocks: Block pointers can be converted to void*.
if (FromType->isBlockPointerType() && ToType->isPointerType() &&
- ToType->getAs<PointerType>()->getPointeeType()->isVoidType()) {
+ ToType->castAs<PointerType>()->getPointeeType()->isVoidType()) {
ConvertedType = ToType;
return true;
}
@@ -3272,7 +3301,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
User.ConversionFunction = Constructor;
User.FoundConversionFunction = Best->FoundDecl;
User.After.setAsIdentityConversion();
- User.After.setFromType(ThisType->getAs<PointerType>()->getPointeeType());
+ User.After.setFromType(ThisType->castAs<PointerType>()->getPointeeType());
User.After.setAllToTypes(ToType);
return Result;
}
@@ -3463,7 +3492,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
User.ConversionFunction = Constructor;
User.FoundConversionFunction = Best->FoundDecl;
User.After.setAsIdentityConversion();
- User.After.setFromType(ThisType->getAs<PointerType>()->getPointeeType());
+ User.After.setFromType(ThisType->castAs<PointerType>()->getPointeeType());
User.After.setAllToTypes(ToType);
return Result;
}
@@ -3755,6 +3784,34 @@ isBetterReferenceBindingKind(const StandardConversionSequence &SCS1,
!SCS2.IsLvalueReference && SCS2.BindsToFunctionLvalue);
}
+enum class FixedEnumPromotion {
+ None,
+ ToUnderlyingType,
+ ToPromotedUnderlyingType
+};
+
+/// Returns kind of fixed enum promotion the \a SCS uses.
+static FixedEnumPromotion
+getFixedEnumPromtion(Sema &S, const StandardConversionSequence &SCS) {
+
+ if (SCS.Second != ICK_Integral_Promotion)
+ return FixedEnumPromotion::None;
+
+ QualType FromType = SCS.getFromType();
+ if (!FromType->isEnumeralType())
+ return FixedEnumPromotion::None;
+
+ EnumDecl *Enum = FromType->getAs<EnumType>()->getDecl();
+ if (!Enum->isFixed())
+ return FixedEnumPromotion::None;
+
+ QualType UnderlyingType = Enum->getIntegerType();
+ if (S.Context.hasSameType(SCS.getToType(1), UnderlyingType))
+ return FixedEnumPromotion::ToUnderlyingType;
+
+ return FixedEnumPromotion::ToPromotedUnderlyingType;
+}
+
/// CompareStandardConversionSequences - Compare two standard
/// conversion sequences to determine whether one is better than the
/// other or if they are indistinguishable (C++ 13.3.3.2p3).
@@ -3796,6 +3853,20 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
? ImplicitConversionSequence::Better
: ImplicitConversionSequence::Worse;
+ // C++14 [over.ics.rank]p4b2:
+ // This is retroactively applied to C++11 by CWG 1601.
+ //
+ // A conversion that promotes an enumeration whose underlying type is fixed
+ // to its underlying type is better than one that promotes to the promoted
+ // underlying type, if the two are different.
+ FixedEnumPromotion FEP1 = getFixedEnumPromtion(S, SCS1);
+ FixedEnumPromotion FEP2 = getFixedEnumPromtion(S, SCS2);
+ if (FEP1 != FixedEnumPromotion::None && FEP2 != FixedEnumPromotion::None &&
+ FEP1 != FEP2)
+ return FEP1 == FixedEnumPromotion::ToUnderlyingType
+ ? ImplicitConversionSequence::Better
+ : ImplicitConversionSequence::Worse;
+
// C++ [over.ics.rank]p4b2:
//
// If class B is derived directly or indirectly from class A,
@@ -4105,14 +4176,14 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
/*FIXME: Remove if Objective-C id conversions get their own rank*/
FromType1->isPointerType() && FromType2->isPointerType() &&
ToType1->isPointerType() && ToType2->isPointerType()) {
- QualType FromPointee1
- = FromType1->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
- QualType ToPointee1
- = ToType1->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
- QualType FromPointee2
- = FromType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
- QualType ToPointee2
- = ToType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
+ QualType FromPointee1 =
+ FromType1->castAs<PointerType>()->getPointeeType().getUnqualifiedType();
+ QualType ToPointee1 =
+ ToType1->castAs<PointerType>()->getPointeeType().getUnqualifiedType();
+ QualType FromPointee2 =
+ FromType2->castAs<PointerType>()->getPointeeType().getUnqualifiedType();
+ QualType ToPointee2 =
+ ToType2->castAs<PointerType>()->getPointeeType().getUnqualifiedType();
// -- conversion of C* to B* is better than conversion of C* to A*,
if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) {
@@ -4301,7 +4372,8 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
QualType OrigT1, QualType OrigT2,
bool &DerivedToBase,
bool &ObjCConversion,
- bool &ObjCLifetimeConversion) {
+ bool &ObjCLifetimeConversion,
+ bool &FunctionConversion) {
assert(!OrigT1->isReferenceType() &&
"T1 must be the pointee type of the reference type");
assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
@@ -4331,15 +4403,16 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
Context.canBindObjCObjectType(UnqualT1, UnqualT2))
ObjCConversion = true;
else if (UnqualT2->isFunctionType() &&
- IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2))
+ IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2)) {
// C++1z [dcl.init.ref]p4:
// cv1 T1" is reference-compatible with "cv2 T2" if [...] T2 is "noexcept
// function" and T1 is "function"
//
// We extend this to also apply to 'noreturn', so allow any function
// conversion between function types.
+ FunctionConversion = true;
return Ref_Compatible;
- else
+ } else
return Ref_Incompatible;
// At this point, we know that T1 and T2 are reference-related (at
@@ -4392,7 +4465,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
bool AllowExplicit) {
assert(T2->isRecordType() && "Can only find conversions of record types.");
CXXRecordDecl *T2RecordDecl
- = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
+ = dyn_cast<CXXRecordDecl>(T2->castAs<RecordType>()->getDecl());
OverloadCandidateSet CandidateSet(
DeclLoc, OverloadCandidateSet::CSK_InitByUserDefinedConversion);
@@ -4420,6 +4493,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
bool DerivedToBase = false;
bool ObjCConversion = false;
bool ObjCLifetimeConversion = false;
+ bool FunctionConversion = false;
// If we are initializing an rvalue reference, don't permit conversion
// functions that return lvalues.
@@ -4432,12 +4506,13 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
if (!ConvTemplate &&
S.CompareReferenceRelationship(
- DeclLoc,
- Conv->getConversionType().getNonReferenceType()
- .getUnqualifiedType(),
- DeclType.getNonReferenceType().getUnqualifiedType(),
- DerivedToBase, ObjCConversion, ObjCLifetimeConversion) ==
- Sema::Ref_Incompatible)
+ DeclLoc,
+ Conv->getConversionType()
+ .getNonReferenceType()
+ .getUnqualifiedType(),
+ DeclType.getNonReferenceType().getUnqualifiedType(),
+ DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
+ FunctionConversion) == Sema::Ref_Incompatible)
continue;
} else {
// If the conversion function doesn't return a reference type,
@@ -4523,7 +4598,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
ImplicitConversionSequence ICS;
ICS.setBad(BadConversionSequence::no_conversion, Init, DeclType);
- QualType T1 = DeclType->getAs<ReferenceType>()->getPointeeType();
+ QualType T1 = DeclType->castAs<ReferenceType>()->getPointeeType();
QualType T2 = Init->getType();
// If the initializer is the address of an overloaded function, try
@@ -4541,11 +4616,11 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
bool DerivedToBase = false;
bool ObjCConversion = false;
bool ObjCLifetimeConversion = false;
+ bool FunctionConversion = false;
Expr::Classification InitCategory = Init->Classify(S.Context);
- Sema::ReferenceCompareResult RefRelationship
- = S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase,
- ObjCConversion, ObjCLifetimeConversion);
-
+ Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(
+ DeclLoc, T1, T2, DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
+ FunctionConversion);
// C++0x [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression
@@ -4920,13 +4995,11 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
// Type is an aggregate, argument is an init list. At this point it comes
// down to checking whether the initialization works.
// FIXME: Find out whether this parameter is consumed or not.
- // FIXME: Expose SemaInit's aggregate initialization code so that we don't
- // need to call into the initialization code here; overload resolution
- // should not be doing that.
InitializedEntity Entity =
InitializedEntity::InitializeParameter(S.Context, ToType,
/*Consumed=*/false);
- if (S.CanPerformCopyInitialization(Entity, From)) {
+ if (S.CanPerformAggregateInitializationForOverloadResolution(Entity,
+ From)) {
Result.setUserDefined();
Result.UserDefined.Before.setAsIdentityConversion();
// Initializer lists don't have a type.
@@ -4949,7 +5022,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
// mention initializer lists in any way. So we go by what list-
// initialization would do and try to extrapolate from that.
- QualType T1 = ToType->getAs<ReferenceType>()->getPointeeType();
+ QualType T1 = ToType->castAs<ReferenceType>()->getPointeeType();
// If the initializer list has a single element that is reference-related
// to the parameter type, we initialize the reference from that.
@@ -4972,9 +5045,10 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
bool dummy1 = false;
bool dummy2 = false;
bool dummy3 = false;
+ bool dummy4 = false;
Sema::ReferenceCompareResult RefRelationship =
S.CompareReferenceRelationship(From->getBeginLoc(), T1, T2, dummy1,
- dummy2, dummy3);
+ dummy2, dummy3, dummy4);
if (RefRelationship >= Sema::Ref_Related) {
return TryReferenceInit(S, Init, ToType, /*FIXME*/ From->getBeginLoc(),
@@ -5219,7 +5293,7 @@ Sema::PerformObjectArgumentInitialization(Expr *From,
CXXMethodDecl *Method) {
QualType FromRecordType, DestType;
QualType ImplicitParamRecordType =
- Method->getThisType()->getAs<PointerType>()->getPointeeType();
+ Method->getThisType()->castAs<PointerType>()->getPointeeType();
Expr::Classification FromClassification;
if (const PointerType *PT = From->getType()->getAs<PointerType>()) {
@@ -5467,6 +5541,14 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
if (Result.isInvalid())
return Result;
+ // C++2a [intro.execution]p5:
+ // A full-expression is [...] a constant-expression [...]
+ Result =
+ S.ActOnFinishFullExpr(Result.get(), From->getExprLoc(),
+ /*DiscardedValue=*/false, /*IsConstexpr=*/true);
+ if (Result.isInvalid())
+ return Result;
+
// Check for a narrowing implicit conversion.
APValue PreNarrowingValue;
QualType PreNarrowingType;
@@ -5998,7 +6080,8 @@ void Sema::AddOverloadCandidate(
FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions,
- ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions) {
+ ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions,
+ OverloadCandidateParamOrder PO) {
const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
assert(Proto && "Functions without a prototype cannot be overloaded");
@@ -6017,25 +6100,14 @@ void Sema::AddOverloadCandidate(
AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(),
Expr::Classification::makeSimpleLValue(), Args,
CandidateSet, SuppressUserConversions,
- PartialOverloading, EarlyConversions);
+ PartialOverloading, EarlyConversions, PO);
return;
}
// We treat a constructor like a non-member function, since its object
// argument doesn't participate in overload resolution.
}
- if (!CandidateSet.isNewCandidate(Function))
- return;
-
- // C++ [over.match.oper]p3:
- // if no operand has a class type, only those non-member functions in the
- // lookup set that have a first parameter of type T1 or "reference to
- // (possibly cv-qualified) T1", when T1 is an enumeration type, or (if there
- // is a right operand) a second parameter of type T2 or "reference to
- // (possibly cv-qualified) T2", when T2 is an enumeration type, are
- // candidate functions.
- if (CandidateSet.getKind() == OverloadCandidateSet::CSK_Operator &&
- !IsAcceptableNonMemberOperatorCandidate(Context, Function, Args))
+ if (!CandidateSet.isNewCandidate(Function, PO))
return;
// C++11 [class.copy]p11: [DR1402]
@@ -6050,12 +6122,25 @@ void Sema::AddOverloadCandidate(
EnterExpressionEvaluationContext Unevaluated(
*this, Sema::ExpressionEvaluationContext::Unevaluated);
+ // C++ [over.match.oper]p3:
+ // if no operand has a class type, only those non-member functions in the
+ // lookup set that have a first parameter of type T1 or "reference to
+ // (possibly cv-qualified) T1", when T1 is an enumeration type, or (if there
+ // is a right operand) a second parameter of type T2 or "reference to
+ // (possibly cv-qualified) T2", when T2 is an enumeration type, are
+ // candidate functions.
+ if (CandidateSet.getKind() == OverloadCandidateSet::CSK_Operator &&
+ !IsAcceptableNonMemberOperatorCandidate(Context, Function, Args))
+ return;
+
// Add this candidate
OverloadCandidate &Candidate =
CandidateSet.addCandidate(Args.size(), EarlyConversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = Function;
Candidate.Viable = true;
+ Candidate.RewriteKind =
+ CandidateSet.getRewriteInfo().getRewriteKind(Function, PO);
Candidate.IsSurrogate = false;
Candidate.IsADLCandidate = IsADLCandidate;
Candidate.IgnoreObjectArgument = false;
@@ -6155,7 +6240,9 @@ void Sema::AddOverloadCandidate(
// Determine the implicit conversion sequences for each of the
// arguments.
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
- if (Candidate.Conversions[ArgIdx].isInitialized()) {
+ unsigned ConvIdx =
+ PO == OverloadCandidateParamOrder::Reversed ? 1 - ArgIdx : ArgIdx;
+ if (Candidate.Conversions[ConvIdx].isInitialized()) {
// We already formed a conversion sequence for this parameter during
// template argument deduction.
} else if (ArgIdx < NumParams) {
@@ -6164,12 +6251,12 @@ void Sema::AddOverloadCandidate(
// (13.3.3.1) that converts that argument to the corresponding
// parameter of F.
QualType ParamType = Proto->getParamType(ArgIdx);
- Candidate.Conversions[ArgIdx] = TryCopyInitialization(
+ Candidate.Conversions[ConvIdx] = TryCopyInitialization(
*this, Args[ArgIdx], ParamType, SuppressUserConversions,
/*InOverloadResolution=*/true,
/*AllowObjCWritebackConversion=*/
getLangOpts().ObjCAutoRefCount, AllowExplicitConversions);
- if (Candidate.Conversions[ArgIdx].isBad()) {
+ if (Candidate.Conversions[ConvIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
return;
@@ -6178,7 +6265,7 @@ void Sema::AddOverloadCandidate(
// (C++ 13.3.2p2): For the purposes of overload resolution, any
// argument for which there is no corresponding parameter is
// considered to ""match the ellipsis" (C+ 13.3.3.1.3).
- Candidate.Conversions[ArgIdx].setEllipsis();
+ Candidate.Conversions[ConvIdx].setEllipsis();
}
}
@@ -6525,9 +6612,10 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
FunctionArgs = Args.slice(1);
}
if (FunTmpl) {
- AddTemplateOverloadCandidate(
- FunTmpl, F.getPair(), ExplicitTemplateArgs, FunctionArgs,
- CandidateSet, SuppressUserConversions, PartialOverloading);
+ AddTemplateOverloadCandidate(FunTmpl, F.getPair(),
+ ExplicitTemplateArgs, FunctionArgs,
+ CandidateSet, SuppressUserConversions,
+ PartialOverloading);
} else {
AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet,
SuppressUserConversions, PartialOverloading);
@@ -6538,12 +6626,12 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
/// AddMethodCandidate - Adds a named decl (which is some kind of
/// method) as a method candidate to the given overload set.
-void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
- QualType ObjectType,
+void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType,
Expr::Classification ObjectClassification,
ArrayRef<Expr *> Args,
- OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions) {
+ OverloadCandidateSet &CandidateSet,
+ bool SuppressUserConversions,
+ OverloadCandidateParamOrder PO) {
NamedDecl *Decl = FoundDecl.getDecl();
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(Decl->getDeclContext());
@@ -6556,11 +6644,11 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
AddMethodTemplateCandidate(TD, FoundDecl, ActingContext,
/*ExplicitArgs*/ nullptr, ObjectType,
ObjectClassification, Args, CandidateSet,
- SuppressUserConversions);
+ SuppressUserConversions, false, PO);
} else {
AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext,
ObjectType, ObjectClassification, Args, CandidateSet,
- SuppressUserConversions);
+ SuppressUserConversions, false, None, PO);
}
}
@@ -6579,14 +6667,15 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
OverloadCandidateSet &CandidateSet,
bool SuppressUserConversions,
bool PartialOverloading,
- ConversionSequenceList EarlyConversions) {
+ ConversionSequenceList EarlyConversions,
+ OverloadCandidateParamOrder PO) {
const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
assert(Proto && "Methods without a prototype cannot be overloaded");
assert(!isa<CXXConstructorDecl>(Method) &&
"Use AddOverloadCandidate for constructors");
- if (!CandidateSet.isNewCandidate(Method))
+ if (!CandidateSet.isNewCandidate(Method, PO))
return;
// C++11 [class.copy]p23: [DR1402]
@@ -6605,6 +6694,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
CandidateSet.addCandidate(Args.size() + 1, EarlyConversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = Method;
+ Candidate.RewriteKind =
+ CandidateSet.getRewriteInfo().getRewriteKind(Method, PO);
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.ExplicitCallArguments = Args.size();
@@ -6640,12 +6731,13 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// The implicit object argument is ignored.
Candidate.IgnoreObjectArgument = true;
else {
+ unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0;
// Determine the implicit conversion sequence for the object
// parameter.
- Candidate.Conversions[0] = TryObjectArgumentInitialization(
+ Candidate.Conversions[ConvIdx] = TryObjectArgumentInitialization(
*this, CandidateSet.getLocation(), ObjectType, ObjectClassification,
Method, ActingContext);
- if (Candidate.Conversions[0].isBad()) {
+ if (Candidate.Conversions[ConvIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
return;
@@ -6664,7 +6756,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// Determine the implicit conversion sequences for each of the
// arguments.
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
- if (Candidate.Conversions[ArgIdx + 1].isInitialized()) {
+ unsigned ConvIdx =
+ PO == OverloadCandidateParamOrder::Reversed ? 0 : (ArgIdx + 1);
+ if (Candidate.Conversions[ConvIdx].isInitialized()) {
// We already formed a conversion sequence for this parameter during
// template argument deduction.
} else if (ArgIdx < NumParams) {
@@ -6673,13 +6767,13 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// (13.3.3.1) that converts that argument to the corresponding
// parameter of F.
QualType ParamType = Proto->getParamType(ArgIdx);
- Candidate.Conversions[ArgIdx + 1]
+ Candidate.Conversions[ConvIdx]
= TryCopyInitialization(*this, Args[ArgIdx], ParamType,
SuppressUserConversions,
/*InOverloadResolution=*/true,
/*AllowObjCWritebackConversion=*/
getLangOpts().ObjCAutoRefCount);
- if (Candidate.Conversions[ArgIdx + 1].isBad()) {
+ if (Candidate.Conversions[ConvIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
return;
@@ -6688,7 +6782,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// (C++ 13.3.2p2): For the purposes of overload resolution, any
// argument for which there is no corresponding parameter is
// considered to "match the ellipsis" (C+ 13.3.3.1.3).
- Candidate.Conversions[ArgIdx + 1].setEllipsis();
+ Candidate.Conversions[ConvIdx].setEllipsis();
}
}
@@ -6709,18 +6803,14 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
/// Add a C++ member function template as a candidate to the candidate
/// set, using template argument deduction to produce an appropriate member
/// function template specialization.
-void
-Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
- DeclAccessPair FoundDecl,
- CXXRecordDecl *ActingContext,
- TemplateArgumentListInfo *ExplicitTemplateArgs,
- QualType ObjectType,
- Expr::Classification ObjectClassification,
- ArrayRef<Expr *> Args,
- OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions,
- bool PartialOverloading) {
- if (!CandidateSet.isNewCandidate(MethodTmpl))
+void Sema::AddMethodTemplateCandidate(
+ FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl,
+ CXXRecordDecl *ActingContext,
+ TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType,
+ Expr::Classification ObjectClassification, ArrayRef<Expr *> Args,
+ OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
+ bool PartialOverloading, OverloadCandidateParamOrder PO) {
+ if (!CandidateSet.isNewCandidate(MethodTmpl, PO))
return;
// C++ [over.match.funcs]p7:
@@ -6741,13 +6831,15 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
return CheckNonDependentConversions(
MethodTmpl, ParamTypes, Args, CandidateSet, Conversions,
SuppressUserConversions, ActingContext, ObjectType,
- ObjectClassification);
+ ObjectClassification, PO);
})) {
OverloadCandidate &Candidate =
CandidateSet.addCandidate(Conversions.size(), Conversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = MethodTmpl->getTemplatedDecl();
Candidate.Viable = false;
+ Candidate.RewriteKind =
+ CandidateSet.getRewriteInfo().getRewriteKind(Candidate.Function, PO);
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument =
cast<CXXMethodDecl>(Candidate.Function)->isStatic() ||
@@ -6771,7 +6863,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
ActingContext, ObjectType, ObjectClassification, Args,
CandidateSet, SuppressUserConversions, PartialOverloading,
- Conversions);
+ Conversions, PO);
}
/// Add a C++ function template specialization as a candidate
@@ -6781,8 +6873,9 @@ void Sema::AddTemplateOverloadCandidate(
FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
- bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate) {
- if (!CandidateSet.isNewCandidate(FunctionTemplate))
+ bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate,
+ OverloadCandidateParamOrder PO) {
+ if (!CandidateSet.isNewCandidate(FunctionTemplate, PO))
return;
// C++ [over.match.funcs]p7:
@@ -6800,15 +6893,17 @@ void Sema::AddTemplateOverloadCandidate(
if (TemplateDeductionResult Result = DeduceTemplateArguments(
FunctionTemplate, ExplicitTemplateArgs, Args, Specialization, Info,
PartialOverloading, [&](ArrayRef<QualType> ParamTypes) {
- return CheckNonDependentConversions(FunctionTemplate, ParamTypes,
- Args, CandidateSet, Conversions,
- SuppressUserConversions);
+ return CheckNonDependentConversions(
+ FunctionTemplate, ParamTypes, Args, CandidateSet, Conversions,
+ SuppressUserConversions, nullptr, QualType(), {}, PO);
})) {
OverloadCandidate &Candidate =
CandidateSet.addCandidate(Conversions.size(), Conversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = FunctionTemplate->getTemplatedDecl();
Candidate.Viable = false;
+ Candidate.RewriteKind =
+ CandidateSet.getRewriteInfo().getRewriteKind(Candidate.Function, PO);
Candidate.IsSurrogate = false;
Candidate.IsADLCandidate = IsADLCandidate;
// Ignore the object argument if there is one, since we don't have an object
@@ -6833,7 +6928,7 @@ void Sema::AddTemplateOverloadCandidate(
AddOverloadCandidate(
Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions,
PartialOverloading, AllowExplicit,
- /*AllowExplicitConversions*/ false, IsADLCandidate, Conversions);
+ /*AllowExplicitConversions*/ false, IsADLCandidate, Conversions, PO);
}
/// Check that implicit conversion sequences can be formed for each argument
@@ -6844,7 +6939,7 @@ bool Sema::CheckNonDependentConversions(
ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet,
ConversionSequenceList &Conversions, bool SuppressUserConversions,
CXXRecordDecl *ActingContext, QualType ObjectType,
- Expr::Classification ObjectClassification) {
+ Expr::Classification ObjectClassification, OverloadCandidateParamOrder PO) {
// FIXME: The cases in which we allow explicit conversions for constructor
// arguments never consider calling a constructor template. It's not clear
// that is correct.
@@ -6867,10 +6962,11 @@ bool Sema::CheckNonDependentConversions(
// overload resolution is permitted to sidestep instantiations.
if (HasThisConversion && !cast<CXXMethodDecl>(FD)->isStatic() &&
!ObjectType.isNull()) {
- Conversions[0] = TryObjectArgumentInitialization(
+ unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0;
+ Conversions[ConvIdx] = TryObjectArgumentInitialization(
*this, CandidateSet.getLocation(), ObjectType, ObjectClassification,
Method, ActingContext);
- if (Conversions[0].isBad())
+ if (Conversions[ConvIdx].isBad())
return true;
}
@@ -6878,14 +6974,17 @@ bool Sema::CheckNonDependentConversions(
++I) {
QualType ParamType = ParamTypes[I];
if (!ParamType->isDependentType()) {
- Conversions[ThisConversions + I]
+ unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed
+ ? 0
+ : (ThisConversions + I);
+ Conversions[ConvIdx]
= TryCopyInitialization(*this, Args[I], ParamType,
SuppressUserConversions,
/*InOverloadResolution=*/true,
/*AllowObjCWritebackConversion=*/
getLangOpts().ObjCAutoRefCount,
AllowExplicit);
- if (Conversions[ThisConversions + I].isBad())
+ if (Conversions[ConvIdx].isBad())
return true;
}
}
@@ -6998,7 +7097,7 @@ void Sema::AddConversionCandidate(
if (const PointerType *FromPtrType = ImplicitParamType->getAs<PointerType>())
ImplicitParamType = FromPtrType->getPointeeType();
CXXRecordDecl *ConversionContext
- = cast<CXXRecordDecl>(ImplicitParamType->getAs<RecordType>()->getDecl());
+ = cast<CXXRecordDecl>(ImplicitParamType->castAs<RecordType>()->getDecl());
Candidate.Conversions[0] = TryObjectArgumentInitialization(
*this, CandidateSet.getLocation(), From->getType(),
@@ -7052,10 +7151,9 @@ void Sema::AddConversionCandidate(
// allocator).
QualType CallResultType = ConversionType.getNonLValueExprType(Context);
- llvm::AlignedCharArray<alignof(CallExpr), sizeof(CallExpr) + sizeof(Stmt *)>
- Buffer;
+ alignas(CallExpr) char Buffer[sizeof(CallExpr) + sizeof(Stmt *)];
CallExpr *TheTemporaryCall = CallExpr::CreateTemporary(
- Buffer.buffer, &ConversionFn, CallResultType, VK, From->getBeginLoc());
+ Buffer, &ConversionFn, CallResultType, VK, From->getBeginLoc());
ImplicitConversionSequence ICS =
TryCopyInitialization(*this, TheTemporaryCall, ToType,
@@ -7274,6 +7372,48 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
}
}
+/// Add all of the non-member operator function declarations in the given
+/// function set to the overload candidate set.
+void Sema::AddNonMemberOperatorCandidates(
+ const UnresolvedSetImpl &Fns, ArrayRef<Expr *> Args,
+ OverloadCandidateSet &CandidateSet,
+ TemplateArgumentListInfo *ExplicitTemplateArgs) {
+ for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) {
+ NamedDecl *D = F.getDecl()->getUnderlyingDecl();
+ ArrayRef<Expr *> FunctionArgs = Args;
+
+ FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D);
+ FunctionDecl *FD =
+ FunTmpl ? FunTmpl->getTemplatedDecl() : cast<FunctionDecl>(D);
+
+ // Don't consider rewritten functions if we're not rewriting.
+ if (!CandidateSet.getRewriteInfo().isAcceptableCandidate(FD))
+ continue;
+
+ assert(!isa<CXXMethodDecl>(FD) &&
+ "unqualified operator lookup found a member function");
+
+ if (FunTmpl) {
+ AddTemplateOverloadCandidate(FunTmpl, F.getPair(), ExplicitTemplateArgs,
+ FunctionArgs, CandidateSet);
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD))
+ AddTemplateOverloadCandidate(
+ FunTmpl, F.getPair(), ExplicitTemplateArgs,
+ {FunctionArgs[1], FunctionArgs[0]}, CandidateSet, false, false,
+ true, ADLCallKind::NotADL, OverloadCandidateParamOrder::Reversed);
+ } else {
+ if (ExplicitTemplateArgs)
+ continue;
+ AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet);
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD))
+ AddOverloadCandidate(FD, F.getPair(),
+ {FunctionArgs[1], FunctionArgs[0]}, CandidateSet,
+ false, false, true, false, ADLCallKind::NotADL,
+ None, OverloadCandidateParamOrder::Reversed);
+ }
+ }
+}
+
/// Add overload candidates for overloaded operators that are
/// member functions.
///
@@ -7285,8 +7425,8 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
SourceLocation OpLoc,
ArrayRef<Expr *> Args,
- OverloadCandidateSet& CandidateSet,
- SourceRange OpRange) {
+ OverloadCandidateSet &CandidateSet,
+ OverloadCandidateParamOrder PO) {
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
// C++ [over.match.oper]p3:
@@ -7321,7 +7461,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
++Oper)
AddMethodCandidate(Oper.getPair(), Args[0]->getType(),
Args[0]->Classify(Context), Args.slice(1),
- CandidateSet, /*SuppressUserConversion=*/false);
+ CandidateSet, /*SuppressUserConversion=*/false, PO);
}
}
@@ -7776,7 +7916,7 @@ class BuiltinOperatorOverloadBuilder {
static constexpr int ArithmeticTypesCap = 24;
SmallVector<CanQualType, ArithmeticTypesCap> ArithmeticTypes;
- // Define some indices used to iterate over the arithemetic types in
+ // Define some indices used to iterate over the arithmetic types in
// ArithmeticTypes. The "promoted arithmetic types" are the arithmetic
// types are that preserved by promotion (C++ [over.built]p2).
unsigned FirstIntegralType,
@@ -8126,10 +8266,16 @@ public:
if (C->Function->isFunctionTemplateSpecialization())
continue;
- QualType FirstParamType =
- C->Function->getParamDecl(0)->getType().getUnqualifiedType();
- QualType SecondParamType =
- C->Function->getParamDecl(1)->getType().getUnqualifiedType();
+ // We interpret "same parameter-type-list" as applying to the
+ // "synthesized candidate, with the order of the two parameters
+ // reversed", not to the original function.
+ bool Reversed = C->RewriteKind & CRK_Reversed;
+ QualType FirstParamType = C->Function->getParamDecl(Reversed ? 1 : 0)
+ ->getType()
+ .getUnqualifiedType();
+ QualType SecondParamType = C->Function->getParamDecl(Reversed ? 0 : 1)
+ ->getType()
+ .getUnqualifiedType();
// Skip if either parameter isn't of enumeral type.
if (!FirstParamType->isEnumeralType() ||
@@ -8759,7 +8905,7 @@ public:
Enum = CandidateTypes[ArgIdx].enumeration_begin(),
EnumEnd = CandidateTypes[ArgIdx].enumeration_end();
Enum != EnumEnd; ++Enum) {
- if (!(*Enum)->getAs<EnumType>()->getDecl()->isScoped())
+ if (!(*Enum)->castAs<EnumType>()->getDecl()->isScoped())
continue;
if (!AddedTypes.insert(S.Context.getCanonicalType(*Enum)).second)
@@ -9183,6 +9329,7 @@ bool clang::isBetterOverloadCandidate(
// A viable function F1 is defined to be a better function than another
// viable function F2 if for all arguments i, ICSi(F1) is not a worse
// conversion sequence than ICSi(F2), and then...
+ bool HasWorseConversion = false;
for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) {
switch (CompareImplicitConversionSequences(S, Loc,
Cand1.Conversions[ArgIdx],
@@ -9193,6 +9340,24 @@ bool clang::isBetterOverloadCandidate(
break;
case ImplicitConversionSequence::Worse:
+ if (Cand1.Function && Cand1.Function == Cand2.Function &&
+ (Cand2.RewriteKind & CRK_Reversed) != 0) {
+ // Work around large-scale breakage caused by considering reversed
+ // forms of operator== in C++20:
+ //
+ // When comparing a function against its reversed form, if we have a
+ // better conversion for one argument and a worse conversion for the
+ // other, we prefer the non-reversed form.
+ //
+ // This prevents a conversion function from being considered ambiguous
+ // with its own reversed form in various where it's only incidentally
+ // heterogeneous.
+ //
+ // We diagnose this as an extension from CreateOverloadedBinOp.
+ HasWorseConversion = true;
+ break;
+ }
+
// Cand1 can't be better than Cand2.
return false;
@@ -9206,6 +9371,8 @@ bool clang::isBetterOverloadCandidate(
// ICSj(F2), or, if not that,
if (HasBetterConversion)
return true;
+ if (HasWorseConversion)
+ return false;
// -- the context is an initialization by user-defined conversion
// (see 8.5, 13.3.1.5) and the standard conversion sequence
@@ -9273,8 +9440,10 @@ bool clang::isBetterOverloadCandidate(
return BetterTemplate == Cand1.Function->getPrimaryTemplate();
}
- // FIXME: Work around a defect in the C++17 inheriting constructor wording.
- // A derived-class constructor beats an (inherited) base class constructor.
+ // -- F1 is a constructor for a class D, F2 is a constructor for a base
+ // class B of D, and for all arguments the corresponding parameters of
+ // F1 and F2 have the same type.
+ // FIXME: Implement the "all parameters have the same type" check.
bool Cand1IsInherited =
dyn_cast_or_null<ConstructorUsingShadowDecl>(Cand1.FoundDecl.getDecl());
bool Cand2IsInherited =
@@ -9292,6 +9461,16 @@ bool clang::isBetterOverloadCandidate(
// Inherited from sibling base classes: still ambiguous.
}
+ // -- F2 is a rewritten candidate (12.4.1.2) and F1 is not
+ // -- F1 and F2 are rewritten candidates, and F2 is a synthesized candidate
+ // with reversed order of parameters and F1 is not
+ //
+ // We rank reversed + different operator as worse than just reversed, but
+ // that comparison can never happen, because we only consider reversing for
+ // the maximally-rewritten operator (== or <=>).
+ if (Cand1.RewriteKind != Cand2.RewriteKind)
+ return Cand1.RewriteKind < Cand2.RewriteKind;
+
// Check C++17 tie-breakers for deduction guides.
{
auto *Guide1 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand1.Function);
@@ -9425,13 +9604,15 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
const FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext);
bool ContainsSameSideCandidate =
llvm::any_of(Candidates, [&](OverloadCandidate *Cand) {
- return Cand->Function &&
+ // Check viable function only.
+ return Cand->Viable && Cand->Function &&
S.IdentifyCUDAPreference(Caller, Cand->Function) ==
Sema::CFP_SameSide;
});
if (ContainsSameSideCandidate) {
auto IsWrongSideCandidate = [&](OverloadCandidate *Cand) {
- return Cand->Function &&
+ // Check viable function only to avoid unnecessary data copying/moving.
+ return Cand->Viable && Cand->Function &&
S.IdentifyCUDAPreference(Caller, Cand->Function) ==
Sema::CFP_WrongSide;
};
@@ -9485,6 +9666,7 @@ namespace {
enum OverloadCandidateKind {
oc_function,
oc_method,
+ oc_reversed_binary_operator,
oc_constructor,
oc_implicit_default_constructor,
oc_implicit_copy_constructor,
@@ -9502,6 +9684,7 @@ enum OverloadCandidateSelect {
static std::pair<OverloadCandidateKind, OverloadCandidateSelect>
ClassifyOverloadCandidate(Sema &S, NamedDecl *Found, FunctionDecl *Fn,
+ OverloadCandidateRewriteKind CRK,
std::string &Description) {
bool isTemplate = Fn->isTemplateDecl() || Found->isTemplateDecl();
@@ -9518,6 +9701,9 @@ ClassifyOverloadCandidate(Sema &S, NamedDecl *Found, FunctionDecl *Fn,
}();
OverloadCandidateKind Kind = [&]() {
+ if (CRK & CRK_Reversed)
+ return oc_reversed_binary_operator;
+
if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn)) {
if (!Ctor->isImplicit()) {
if (isa<ConstructorUsingShadowDecl>(Found))
@@ -9642,6 +9828,7 @@ bool Sema::checkAddressOfFunctionIsAvailable(const FunctionDecl *Function,
// Notes the location of an overload candidate.
void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn,
+ OverloadCandidateRewriteKind RewriteKind,
QualType DestType, bool TakingAddress) {
if (TakingAddress && !checkAddressOfCandidateIsAvailable(*this, Fn))
return;
@@ -9651,7 +9838,7 @@ void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn,
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> KSPair =
- ClassifyOverloadCandidate(*this, Found, Fn, FnDesc);
+ ClassifyOverloadCandidate(*this, Found, Fn, RewriteKind, FnDesc);
PartialDiagnostic PD = PDiag(diag::note_ovl_candidate)
<< (unsigned)KSPair.first << (unsigned)KSPair.second
<< Fn << FnDesc;
@@ -9675,11 +9862,11 @@ void Sema::NoteAllOverloadCandidates(Expr *OverloadedExpr, QualType DestType,
I != IEnd; ++I) {
if (FunctionTemplateDecl *FunTmpl =
dyn_cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl()) ) {
- NoteOverloadCandidate(*I, FunTmpl->getTemplatedDecl(), DestType,
+ NoteOverloadCandidate(*I, FunTmpl->getTemplatedDecl(), CRK_None, DestType,
TakingAddress);
} else if (FunctionDecl *Fun
= dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()) ) {
- NoteOverloadCandidate(*I, Fun, DestType, TakingAddress);
+ NoteOverloadCandidate(*I, Fun, CRK_None, DestType, TakingAddress);
}
}
}
@@ -9729,7 +9916,8 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
- ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, FnDesc);
+ ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Cand->RewriteKind,
+ FnDesc);
Expr *FromExpr = Conv.Bad.FromExpr;
QualType FromTy = Conv.Bad.getFromType();
@@ -10001,7 +10189,7 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D,
std::string Description;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
- ClassifyOverloadCandidate(S, Found, Fn, Description);
+ ClassifyOverloadCandidate(S, Found, Fn, CRK_None, Description);
if (modeCount == 1 && Fn->getParamDecl(0)->getDeclName())
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity_one)
@@ -10298,7 +10486,8 @@ static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) {
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
- ClassifyOverloadCandidate(S, Cand->FoundDecl, Callee, FnDesc);
+ ClassifyOverloadCandidate(S, Cand->FoundDecl, Callee, Cand->RewriteKind,
+ FnDesc);
S.Diag(Callee->getLocation(), diag::note_ovl_candidate_bad_target)
<< (unsigned)FnKindPair.first << (unsigned)ocs_non_template
@@ -10416,7 +10605,8 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
if (Fn->isDeleted()) {
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
- ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, FnDesc);
+ ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Cand->RewriteKind,
+ FnDesc);
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
@@ -10426,7 +10616,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
}
// We don't really have anything else to say about viable candidates.
- S.NoteOverloadCandidate(Cand->FoundDecl, Fn);
+ S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind);
return;
}
@@ -10459,7 +10649,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_trivial_conversion:
case ovl_fail_bad_final_conversion:
case ovl_fail_final_conversion_not_exact:
- return S.NoteOverloadCandidate(Cand->FoundDecl, Fn);
+ return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind);
case ovl_fail_bad_conversion: {
unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0);
@@ -10470,7 +10660,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
// FIXME: this currently happens when we're called from SemaInit
// when user-conversion overload fails. Figure out how to handle
// those conditions and diagnose them well.
- return S.NoteOverloadCandidate(Cand->FoundDecl, Fn);
+ return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind);
}
case ovl_fail_bad_target:
@@ -10550,12 +10740,12 @@ static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc,
TypeStr += Cand->BuiltinParamTypes[0].getAsString();
if (Cand->Conversions.size() == 1) {
TypeStr += ")";
- S.Diag(OpLoc, diag::note_ovl_builtin_unary_candidate) << TypeStr;
+ S.Diag(OpLoc, diag::note_ovl_builtin_candidate) << TypeStr;
} else {
TypeStr += ", ";
TypeStr += Cand->BuiltinParamTypes[1].getAsString();
TypeStr += ")";
- S.Diag(OpLoc, diag::note_ovl_builtin_binary_candidate) << TypeStr;
+ S.Diag(OpLoc, diag::note_ovl_builtin_candidate) << TypeStr;
}
}
@@ -10746,8 +10936,10 @@ struct CompareOverloadCandidatesForDisplay {
/// CompleteNonViableCandidate - Normally, overload resolution only
/// computes up to the first bad conversion. Produces the FixIt set if
/// possible.
-static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
- ArrayRef<Expr *> Args) {
+static void
+CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
+ ArrayRef<Expr *> Args,
+ OverloadCandidateSet::CandidateSetKind CSK) {
assert(!Cand->Viable);
// Don't do anything on failures other than bad conversion.
@@ -10775,6 +10967,7 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
bool SuppressUserConversions = false;
unsigned ConvIdx = 0;
+ unsigned ArgIdx = 0;
ArrayRef<QualType> ParamTypes;
if (Cand->IsSurrogate) {
@@ -10782,16 +10975,19 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
= Cand->Surrogate->getConversionType().getNonReferenceType();
if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
ConvType = ConvPtrType->getPointeeType();
- ParamTypes = ConvType->getAs<FunctionProtoType>()->getParamTypes();
- // Conversion 0 is 'this', which doesn't have a corresponding argument.
+ ParamTypes = ConvType->castAs<FunctionProtoType>()->getParamTypes();
+ // Conversion 0 is 'this', which doesn't have a corresponding parameter.
ConvIdx = 1;
} else if (Cand->Function) {
ParamTypes =
- Cand->Function->getType()->getAs<FunctionProtoType>()->getParamTypes();
+ Cand->Function->getType()->castAs<FunctionProtoType>()->getParamTypes();
if (isa<CXXMethodDecl>(Cand->Function) &&
!isa<CXXConstructorDecl>(Cand->Function)) {
- // Conversion 0 is 'this', which doesn't have a corresponding argument.
+ // Conversion 0 is 'this', which doesn't have a corresponding parameter.
ConvIdx = 1;
+ if (CSK == OverloadCandidateSet::CSK_Operator)
+ // Argument 0 is 'this', which doesn't have a corresponding parameter.
+ ArgIdx = 1;
}
} else {
// Builtin operator.
@@ -10800,16 +10996,19 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
}
// Fill in the rest of the conversions.
- for (unsigned ArgIdx = 0; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) {
+ bool Reversed = Cand->RewriteKind & CRK_Reversed;
+ for (unsigned ParamIdx = Reversed ? ParamTypes.size() - 1 : 0;
+ ConvIdx != ConvCount;
+ ++ConvIdx, ++ArgIdx, ParamIdx += (Reversed ? -1 : 1)) {
if (Cand->Conversions[ConvIdx].isInitialized()) {
// We've already checked this conversion.
} else if (ArgIdx < ParamTypes.size()) {
- if (ParamTypes[ArgIdx]->isDependentType())
+ if (ParamTypes[ParamIdx]->isDependentType())
Cand->Conversions[ConvIdx].setAsIdentityConversion(
Args[ArgIdx]->getType());
else {
Cand->Conversions[ConvIdx] =
- TryCopyInitialization(S, Args[ArgIdx], ParamTypes[ArgIdx],
+ TryCopyInitialization(S, Args[ArgIdx], ParamTypes[ParamIdx],
SuppressUserConversions,
/*InOverloadResolution=*/true,
/*AllowObjCWritebackConversion=*/
@@ -10837,7 +11036,7 @@ SmallVector<OverloadCandidate *, 32> OverloadCandidateSet::CompleteCandidates(
if (Cand->Viable)
Cands.push_back(Cand);
else if (OCD == OCD_AllCandidates) {
- CompleteNonViableCandidate(S, Cand, Args);
+ CompleteNonViableCandidate(S, Cand, Args, Kind);
if (Cand->Function || Cand->IsSurrogate)
Cands.push_back(Cand);
// Otherwise, this a non-viable builtin candidate. We do not, in general,
@@ -11394,7 +11593,7 @@ public:
if (FunctionDecl *Fun =
dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()))
if (!functionHasPassObjectSizeParams(Fun))
- S.NoteOverloadCandidate(*I, Fun, TargetFunctionType,
+ S.NoteOverloadCandidate(*I, Fun, CRK_None, TargetFunctionType,
/*TakingAddress=*/true);
FailedCandidates.NoteCandidates(S, OvlExpr->getBeginLoc());
}
@@ -12344,7 +12543,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator);
// Add the candidates from the given function set.
- AddFunctionCandidates(Fns, ArgsArray, CandidateSet);
+ AddNonMemberOperatorCandidates(Fns, ArgsArray, CandidateSet);
// Add operator candidates that are member functions.
AddMemberOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
@@ -12489,14 +12688,17 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
///
/// \param LHS Left-hand argument.
/// \param RHS Right-hand argument.
-ExprResult
-Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
- BinaryOperatorKind Opc,
- const UnresolvedSetImpl &Fns,
- Expr *LHS, Expr *RHS, bool PerformADL) {
+ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
+ BinaryOperatorKind Opc,
+ const UnresolvedSetImpl &Fns, Expr *LHS,
+ Expr *RHS, bool PerformADL,
+ bool AllowRewrittenCandidates) {
Expr *Args[2] = { LHS, RHS };
LHS=RHS=nullptr; // Please use only Args instead of LHS/RHS couple
+ if (!getLangOpts().CPlusPlus2a)
+ AllowRewrittenCandidates = false;
+
OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc);
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
@@ -12554,23 +12756,61 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
// Build an empty overload set.
- OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator);
+ OverloadCandidateSet CandidateSet(
+ OpLoc, OverloadCandidateSet::CSK_Operator,
+ OverloadCandidateSet::OperatorRewriteInfo(Op, AllowRewrittenCandidates));
- // Add the candidates from the given function set.
- AddFunctionCandidates(Fns, Args, CandidateSet);
+ OverloadedOperatorKind ExtraOp =
+ AllowRewrittenCandidates ? getRewrittenOverloadedOperator(Op) : OO_None;
+
+ // Add the candidates from the given function set. This also adds the
+ // rewritten candidates using these functions if necessary.
+ AddNonMemberOperatorCandidates(Fns, Args, CandidateSet);
// Add operator candidates that are member functions.
AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet);
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(Op))
+ AddMemberOperatorCandidates(Op, OpLoc, {Args[1], Args[0]}, CandidateSet,
+ OverloadCandidateParamOrder::Reversed);
+
+ // In C++20, also add any rewritten member candidates.
+ if (ExtraOp) {
+ AddMemberOperatorCandidates(ExtraOp, OpLoc, Args, CandidateSet);
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(ExtraOp))
+ AddMemberOperatorCandidates(ExtraOp, OpLoc, {Args[1], Args[0]},
+ CandidateSet,
+ OverloadCandidateParamOrder::Reversed);
+ }
// Add candidates from ADL. Per [over.match.oper]p2, this lookup is not
// performed for an assignment operator (nor for operator[] nor operator->,
// which don't get here).
- if (Opc != BO_Assign && PerformADL)
+ if (Opc != BO_Assign && PerformADL) {
AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,
/*ExplicitTemplateArgs*/ nullptr,
CandidateSet);
+ if (ExtraOp) {
+ DeclarationName ExtraOpName =
+ Context.DeclarationNames.getCXXOperatorName(ExtraOp);
+ AddArgumentDependentLookupCandidates(ExtraOpName, OpLoc, Args,
+ /*ExplicitTemplateArgs*/ nullptr,
+ CandidateSet);
+ }
+ }
// Add builtin operator candidates.
+ //
+ // FIXME: We don't add any rewritten candidates here. This is strictly
+ // incorrect; a builtin candidate could be hidden by a non-viable candidate,
+ // resulting in our selecting a rewritten builtin candidate. For example:
+ //
+ // enum class E { e };
+ // bool operator!=(E, E) requires false;
+ // bool k = E::e != E::e;
+ //
+ // ... should select the rewritten builtin candidate 'operator==(E, E)'. But
+ // it seems unreasonable to consider rewritten builtin candidates. A core
+ // issue has been filed proposing to removed this requirement.
AddBuiltinOperatorCandidates(Op, OpLoc, Args, CandidateSet);
bool HadMultipleCandidates = (CandidateSet.size() > 1);
@@ -12582,11 +12822,57 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// We found a built-in operator or an overloaded operator.
FunctionDecl *FnDecl = Best->Function;
+ bool IsReversed = (Best->RewriteKind & CRK_Reversed);
+ if (IsReversed)
+ std::swap(Args[0], Args[1]);
+
if (FnDecl) {
Expr *Base = nullptr;
// We matched an overloaded operator. Build a call to that
// operator.
+ OverloadedOperatorKind ChosenOp =
+ FnDecl->getDeclName().getCXXOverloadedOperator();
+
+ // C++2a [over.match.oper]p9:
+ // If a rewritten operator== candidate is selected by overload
+ // resolution for an operator@, its return type shall be cv bool
+ if (Best->RewriteKind && ChosenOp == OO_EqualEqual &&
+ !FnDecl->getReturnType()->isBooleanType()) {
+ Diag(OpLoc, diag::err_ovl_rewrite_equalequal_not_bool)
+ << FnDecl->getReturnType() << BinaryOperator::getOpcodeStr(Opc)
+ << Args[0]->getSourceRange() << Args[1]->getSourceRange();
+ Diag(FnDecl->getLocation(), diag::note_declared_at);
+ return ExprError();
+ }
+
+ if (AllowRewrittenCandidates && !IsReversed &&
+ CandidateSet.getRewriteInfo().shouldAddReversed(ChosenOp)) {
+ // We could have reversed this operator, but didn't. Check if the
+ // reversed form was a viable candidate, and if so, if it had a
+ // better conversion for either parameter. If so, this call is
+ // formally ambiguous, and allowing it is an extension.
+ for (OverloadCandidate &Cand : CandidateSet) {
+ if (Cand.Viable && Cand.Function == FnDecl &&
+ Cand.RewriteKind & CRK_Reversed) {
+ for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) {
+ if (CompareImplicitConversionSequences(
+ *this, OpLoc, Cand.Conversions[ArgIdx],
+ Best->Conversions[ArgIdx]) ==
+ ImplicitConversionSequence::Better) {
+ Diag(OpLoc, diag::ext_ovl_ambiguous_oper_binary_reversed)
+ << BinaryOperator::getOpcodeStr(Opc)
+ << Args[0]->getType() << Args[1]->getType()
+ << Args[0]->getSourceRange() << Args[1]->getSourceRange();
+ Diag(FnDecl->getLocation(),
+ diag::note_ovl_ambiguous_oper_binary_reversed_candidate);
+ }
+ }
+ break;
+ }
+ }
+ }
+
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
// Best->Access is only meaningful for class members.
@@ -12640,8 +12926,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
ResultTy = ResultTy.getNonLValueExprType(Context);
CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
- Context, Op, FnExpr.get(), Args, ResultTy, VK, OpLoc, FPFeatures,
- Best->IsADLCandidate);
+ Context, ChosenOp, FnExpr.get(), Args, ResultTy, VK, OpLoc,
+ FPFeatures, Best->IsADLCandidate);
if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall,
FnDecl))
@@ -12663,7 +12949,46 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
isa<CXXMethodDecl>(FnDecl), OpLoc, TheCall->getSourceRange(),
VariadicDoesNotApply);
- return MaybeBindToTemporary(TheCall);
+ ExprResult R = MaybeBindToTemporary(TheCall);
+ if (R.isInvalid())
+ return ExprError();
+
+ // For a rewritten candidate, we've already reversed the arguments
+ // if needed. Perform the rest of the rewrite now.
+ if ((Best->RewriteKind & CRK_DifferentOperator) ||
+ (Op == OO_Spaceship && IsReversed)) {
+ if (Op == OO_ExclaimEqual) {
+ assert(ChosenOp == OO_EqualEqual && "unexpected operator name");
+ R = CreateBuiltinUnaryOp(OpLoc, UO_LNot, R.get());
+ } else {
+ assert(ChosenOp == OO_Spaceship && "unexpected operator name");
+ llvm::APSInt Zero(Context.getTypeSize(Context.IntTy), false);
+ Expr *ZeroLiteral =
+ IntegerLiteral::Create(Context, Zero, Context.IntTy, OpLoc);
+
+ Sema::CodeSynthesisContext Ctx;
+ Ctx.Kind = Sema::CodeSynthesisContext::RewritingOperatorAsSpaceship;
+ Ctx.Entity = FnDecl;
+ pushCodeSynthesisContext(Ctx);
+
+ R = CreateOverloadedBinOp(
+ OpLoc, Opc, Fns, IsReversed ? ZeroLiteral : R.get(),
+ IsReversed ? R.get() : ZeroLiteral, PerformADL,
+ /*AllowRewrittenCandidates=*/false);
+
+ popCodeSynthesisContext();
+ }
+ if (R.isInvalid())
+ return ExprError();
+ } else {
+ assert(ChosenOp == Op && "unexpected operator name");
+ }
+
+ // Make a note in the AST if we did any rewriting.
+ if (Best->RewriteKind != CRK_None)
+ R = new (Context) CXXRewrittenBinaryOperator(R.get(), IsReversed);
+
+ return R;
} else {
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
@@ -12753,10 +13078,12 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return ExprError();
}
CandidateSet.NoteCandidates(
- PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_deleted_oper)
- << BinaryOperator::getOpcodeStr(Opc)
- << Args[0]->getSourceRange()
- << Args[1]->getSourceRange()),
+ PartialDiagnosticAt(
+ OpLoc, PDiag(diag::err_ovl_deleted_oper)
+ << getOperatorSpelling(Best->Function->getDeclName()
+ .getCXXOverloadedOperator())
+ << Args[0]->getSourceRange()
+ << Args[1]->getSourceRange()),
*this, OCD_AllCandidates, Args, BinaryOperator::getOpcodeStr(Opc),
OpLoc);
return ExprError();
@@ -13633,8 +13960,8 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
OverloadCandidateSet CandidateSet(UDSuffixLoc,
OverloadCandidateSet::CSK_Normal);
- AddFunctionCandidates(R.asUnresolvedSet(), Args, CandidateSet, TemplateArgs,
- /*SuppressUserConversions=*/true);
+ AddNonMemberOperatorCandidates(R.asUnresolvedSet(), Args, CandidateSet,
+ TemplateArgs);
bool HadMultipleCandidates = (CandidateSet.size() > 1);
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 480155df8990..6c680f29da4f 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -196,6 +196,25 @@ static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) {
return true;
}
+static bool DiagnoseNoDiscard(Sema &S, const WarnUnusedResultAttr *A,
+ SourceLocation Loc, SourceRange R1,
+ SourceRange R2, bool IsCtor) {
+ if (!A)
+ return false;
+ StringRef Msg = A->getMessage();
+
+ if (Msg.empty()) {
+ if (IsCtor)
+ return S.Diag(Loc, diag::warn_unused_constructor) << A << R1 << R2;
+ return S.Diag(Loc, diag::warn_unused_result) << A << R1 << R2;
+ }
+
+ if (IsCtor)
+ return S.Diag(Loc, diag::warn_unused_constructor_msg) << A << Msg << R1
+ << R2;
+ return S.Diag(Loc, diag::warn_unused_result_msg) << A << Msg << R1 << R2;
+}
+
void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
if (const LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S))
return DiagnoseUnusedExprResult(Label->getSubStmt());
@@ -254,14 +273,19 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
return;
E = WarnExpr;
+ if (const auto *Cast = dyn_cast<CastExpr>(E))
+ if (Cast->getCastKind() == CK_NoOp ||
+ Cast->getCastKind() == CK_ConstructorConversion)
+ E = Cast->getSubExpr()->IgnoreImpCasts();
+
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
if (E->getType()->isVoidType())
return;
- if (const Attr *A = CE->getUnusedResultAttr(Context)) {
- Diag(Loc, diag::warn_unused_result) << A << R1 << R2;
+ if (DiagnoseNoDiscard(*this, cast_or_null<WarnUnusedResultAttr>(
+ CE->getUnusedResultAttr(Context)),
+ Loc, R1, R2, /*isCtor=*/false))
return;
- }
// If the callee has attribute pure, const, or warn_unused_result, warn with
// a more specific message to make it clear what is happening. If the call
@@ -279,9 +303,24 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
return;
}
}
+ } else if (const auto *CE = dyn_cast<CXXConstructExpr>(E)) {
+ if (const CXXConstructorDecl *Ctor = CE->getConstructor()) {
+ const auto *A = Ctor->getAttr<WarnUnusedResultAttr>();
+ A = A ? A : Ctor->getParent()->getAttr<WarnUnusedResultAttr>();
+ if (DiagnoseNoDiscard(*this, A, Loc, R1, R2, /*isCtor=*/true))
+ return;
+ }
+ } else if (const auto *ILE = dyn_cast<InitListExpr>(E)) {
+ if (const TagDecl *TD = ILE->getType()->getAsTagDecl()) {
+
+ if (DiagnoseNoDiscard(*this, TD->getAttr<WarnUnusedResultAttr>(), Loc, R1,
+ R2, /*isCtor=*/false))
+ return;
+ }
} else if (ShouldSuppress)
return;
+ E = WarnExpr;
if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
if (getLangOpts().ObjCAutoRefCount && ME->isDelegateInitCall()) {
Diag(Loc, diag::err_arc_unused_init_message) << R1;
@@ -289,10 +328,9 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
}
const ObjCMethodDecl *MD = ME->getMethodDecl();
if (MD) {
- if (const auto *A = MD->getAttr<WarnUnusedResultAttr>()) {
- Diag(Loc, diag::warn_unused_result) << A << R1 << R2;
+ if (DiagnoseNoDiscard(*this, MD->getAttr<WarnUnusedResultAttr>(), Loc, R1,
+ R2, /*isCtor=*/false))
return;
- }
}
} else if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) {
const Expr *Source = POE->getSyntacticForm();
@@ -392,45 +430,44 @@ Sema::ActOnCaseExpr(SourceLocation CaseLoc, ExprResult Val) {
// If we're not inside a switch, let the 'case' statement handling diagnose
// this. Just clean up after the expression as best we can.
- if (!getCurFunction()->SwitchStack.empty()) {
- Expr *CondExpr =
- getCurFunction()->SwitchStack.back().getPointer()->getCond();
- if (!CondExpr)
- return ExprError();
- QualType CondType = CondExpr->getType();
-
- auto CheckAndFinish = [&](Expr *E) {
- if (CondType->isDependentType() || E->isTypeDependent())
- return ExprResult(E);
-
- if (getLangOpts().CPlusPlus11) {
- // C++11 [stmt.switch]p2: the constant-expression shall be a converted
- // constant expression of the promoted type of the switch condition.
- llvm::APSInt TempVal;
- return CheckConvertedConstantExpression(E, CondType, TempVal,
- CCEK_CaseValue);
- }
+ if (getCurFunction()->SwitchStack.empty())
+ return ActOnFinishFullExpr(Val.get(), Val.get()->getExprLoc(), false,
+ getLangOpts().CPlusPlus11);
- ExprResult ER = E;
- if (!E->isValueDependent())
- ER = VerifyIntegerConstantExpression(E);
- if (!ER.isInvalid())
- ER = DefaultLvalueConversion(ER.get());
- if (!ER.isInvalid())
- ER = ImpCastExprToType(ER.get(), CondType, CK_IntegralCast);
- return ER;
- };
+ Expr *CondExpr =
+ getCurFunction()->SwitchStack.back().getPointer()->getCond();
+ if (!CondExpr)
+ return ExprError();
+ QualType CondType = CondExpr->getType();
- ExprResult Converted = CorrectDelayedTyposInExpr(Val, CheckAndFinish);
- if (Converted.get() == Val.get())
- Converted = CheckAndFinish(Val.get());
- if (Converted.isInvalid())
- return ExprError();
- Val = Converted;
- }
+ auto CheckAndFinish = [&](Expr *E) {
+ if (CondType->isDependentType() || E->isTypeDependent())
+ return ExprResult(E);
+
+ if (getLangOpts().CPlusPlus11) {
+ // C++11 [stmt.switch]p2: the constant-expression shall be a converted
+ // constant expression of the promoted type of the switch condition.
+ llvm::APSInt TempVal;
+ return CheckConvertedConstantExpression(E, CondType, TempVal,
+ CCEK_CaseValue);
+ }
- return ActOnFinishFullExpr(Val.get(), Val.get()->getExprLoc(), false,
- getLangOpts().CPlusPlus11);
+ ExprResult ER = E;
+ if (!E->isValueDependent())
+ ER = VerifyIntegerConstantExpression(E);
+ if (!ER.isInvalid())
+ ER = DefaultLvalueConversion(ER.get());
+ if (!ER.isInvalid())
+ ER = ImpCastExprToType(ER.get(), CondType, CK_IntegralCast);
+ if (!ER.isInvalid())
+ ER = ActOnFinishFullExpr(ER.get(), ER.get()->getExprLoc(), false);
+ return ER;
+ };
+
+ ExprResult Converted = CorrectDelayedTyposInExpr(Val, CheckAndFinish);
+ if (Converted.get() == Val.get())
+ Converted = CheckAndFinish(Val.get());
+ return Converted;
}
StmtResult
@@ -926,7 +963,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// condition is constant.
llvm::APSInt ConstantCondValue;
bool HasConstantCond = false;
- if (!HasDependentValue && !TheDefaultStmt) {
+ if (!TheDefaultStmt) {
Expr::EvalResult Result;
HasConstantCond = CondExpr->EvaluateAsInt(Result, Context,
Expr::SE_AllowSideEffects);
@@ -2637,6 +2674,11 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc,
if (Kind == BFRK_Check)
return StmtResult();
+ // In OpenMP loop region loop control variable must be private. Perform
+ // analysis of first part (if any).
+ if (getLangOpts().OpenMP >= 50 && BeginDeclStmt.isUsable())
+ ActOnOpenMPLoopInitialization(ForLoc, BeginDeclStmt.get());
+
return new (Context) CXXForRangeStmt(
InitStmt, RangeDS, cast_or_null<DeclStmt>(BeginDeclStmt.get()),
cast_or_null<DeclStmt>(EndDeclStmt.get()), NotEqExpr.get(),
@@ -3268,18 +3310,18 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
}
assert(!FnRetType.isNull());
- if (BlockScopeInfo *CurBlock = dyn_cast<BlockScopeInfo>(CurCap)) {
- if (CurBlock->FunctionType->getAs<FunctionType>()->getNoReturnAttr()) {
+ if (auto *CurBlock = dyn_cast<BlockScopeInfo>(CurCap)) {
+ if (CurBlock->FunctionType->castAs<FunctionType>()->getNoReturnAttr()) {
Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr);
return StmtError();
}
- } else if (CapturedRegionScopeInfo *CurRegion =
- dyn_cast<CapturedRegionScopeInfo>(CurCap)) {
+ } else if (auto *CurRegion = dyn_cast<CapturedRegionScopeInfo>(CurCap)) {
Diag(ReturnLoc, diag::err_return_in_captured_stmt) << CurRegion->getRegionName();
return StmtError();
} else {
assert(CurLambda && "unknown kind of captured scope");
- if (CurLambda->CallOperator->getType()->getAs<FunctionType>()
+ if (CurLambda->CallOperator->getType()
+ ->castAs<FunctionType>()
->getNoReturnAttr()) {
Diag(ReturnLoc, diag::err_noreturn_lambda_has_return_expr);
return StmtError();
@@ -3463,6 +3505,14 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
return true;
}
+ // CUDA: Kernel function must have 'void' return type.
+ if (getLangOpts().CUDA)
+ if (FD->hasAttr<CUDAGlobalAttr>() && !Deduced->isVoidType()) {
+ Diag(FD->getLocation(), diag::err_kern_type_not_void_return)
+ << FD->getType() << FD->getSourceRange();
+ return true;
+ }
+
// If a function with a declared return type that contains a placeholder type
// has multiple return statements, the return type is deduced for each return
// statement. [...] if the type deduced is not the same in each deduction,
@@ -4296,7 +4346,8 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
CapturedRegionKind Kind,
- ArrayRef<CapturedParamNameType> Params) {
+ ArrayRef<CapturedParamNameType> Params,
+ unsigned OpenMPCaptureLevel) {
CapturedDecl *CD = nullptr;
RecordDecl *RD = CreateCapturedStmtRecordDecl(CD, Loc, Params.size());
@@ -4341,7 +4392,7 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
CD->setContextParam(ParamNum, Param);
}
// Enter the capturing scope for this captured region.
- PushCapturedRegionScope(CurScope, CD, RD, Kind);
+ PushCapturedRegionScope(CurScope, CD, RD, Kind, OpenMPCaptureLevel);
if (CurScope)
PushDeclContext(CurScope, CD);
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index b123a739a7ab..9b051e02d127 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -383,25 +383,19 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
} else if (Info.requiresImmediateConstant() && !Info.allowsRegister()) {
if (!InputExpr->isValueDependent()) {
Expr::EvalResult EVResult;
- if (!InputExpr->EvaluateAsRValue(EVResult, Context, true))
- return StmtError(
- Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected)
- << Info.getConstraintStr() << InputExpr->getSourceRange());
-
- // For compatibility with GCC, we also allow pointers that would be
- // integral constant expressions if they were cast to int.
- llvm::APSInt IntResult;
- if (!EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(),
- Context))
- return StmtError(
- Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected)
- << Info.getConstraintStr() << InputExpr->getSourceRange());
-
- if (!Info.isValidAsmImmediate(IntResult))
- return StmtError(Diag(InputExpr->getBeginLoc(),
- diag::err_invalid_asm_value_for_constraint)
- << IntResult.toString(10) << Info.getConstraintStr()
- << InputExpr->getSourceRange());
+ if (InputExpr->EvaluateAsRValue(EVResult, Context, true)) {
+ // For compatibility with GCC, we also allow pointers that would be
+ // integral constant expressions if they were cast to int.
+ llvm::APSInt IntResult;
+ if (EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(),
+ Context))
+ if (!Info.isValidAsmImmediate(IntResult))
+ return StmtError(Diag(InputExpr->getBeginLoc(),
+ diag::err_invalid_asm_value_for_constraint)
+ << IntResult.toString(10)
+ << Info.getConstraintStr()
+ << InputExpr->getSourceRange());
+ }
}
} else {
diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp
index 791c52c2d913..3d91893b4065 100644
--- a/lib/Sema/SemaStmtAttr.cpp
+++ b/lib/Sema/SemaStmtAttr.cpp
@@ -23,8 +23,7 @@ using namespace sema;
static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const ParsedAttr &A,
SourceRange Range) {
- FallThroughAttr Attr(A.getRange(), S.Context,
- A.getAttributeSpellingListIndex());
+ FallThroughAttr Attr(S.Context, A);
if (!isa<NullStmt>(St)) {
S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target)
<< Attr.getSpelling() << St->getBeginLoc();
@@ -45,10 +44,10 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const ParsedAttr &A,
// about using it as an extension.
if (!S.getLangOpts().CPlusPlus17 && A.isCXX11Attribute() &&
!A.getScopeName())
- S.Diag(A.getLoc(), diag::ext_cxx17_attr) << A.getName();
+ S.Diag(A.getLoc(), diag::ext_cxx17_attr) << A;
FnScope->setHasFallthroughStmt();
- return ::new (S.Context) auto(Attr);
+ return ::new (S.Context) FallThroughAttr(S.Context, A);
}
static Attr *handleSuppressAttr(Sema &S, Stmt *St, const ParsedAttr &A,
@@ -71,8 +70,7 @@ static Attr *handleSuppressAttr(Sema &S, Stmt *St, const ParsedAttr &A,
}
return ::new (S.Context) SuppressAttr(
- A.getRange(), S.Context, DiagnosticIdentifiers.data(),
- DiagnosticIdentifiers.size(), A.getAttributeSpellingListIndex());
+ S.Context, A, DiagnosticIdentifiers.data(), DiagnosticIdentifiers.size());
}
static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
@@ -97,8 +95,6 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
return nullptr;
}
- LoopHintAttr::Spelling Spelling =
- LoopHintAttr::Spelling(A.getAttributeSpellingListIndex());
LoopHintAttr::OptionType Option;
LoopHintAttr::LoopHintState State;
@@ -133,6 +129,7 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
.Case("vectorize", LoopHintAttr::Vectorize)
.Case("vectorize_width", LoopHintAttr::VectorizeWidth)
.Case("interleave", LoopHintAttr::Interleave)
+ .Case("vectorize_predicate", LoopHintAttr::VectorizePredicate)
.Case("interleave_count", LoopHintAttr::InterleaveCount)
.Case("unroll", LoopHintAttr::Unroll)
.Case("unroll_count", LoopHintAttr::UnrollCount)
@@ -151,6 +148,7 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
State = LoopHintAttr::Numeric;
} else if (Option == LoopHintAttr::Vectorize ||
Option == LoopHintAttr::Interleave ||
+ Option == LoopHintAttr::VectorizePredicate ||
Option == LoopHintAttr::Unroll ||
Option == LoopHintAttr::Distribute ||
Option == LoopHintAttr::PipelineDisabled) {
@@ -169,8 +167,7 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
llvm_unreachable("bad loop hint");
}
- return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State,
- ValueExpr, A.getRange());
+ return LoopHintAttr::CreateImplicit(S.Context, Option, State, ValueExpr, A);
}
static void
@@ -189,7 +186,8 @@ CheckForIncompatibleAttributes(Sema &S,
const LoopHintAttr *StateAttr;
const LoopHintAttr *NumericAttr;
} HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr},
- {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}};
+ {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr},
+ {nullptr, nullptr}};
for (const auto *I : Attrs) {
const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
@@ -205,7 +203,8 @@ CheckForIncompatibleAttributes(Sema &S,
Unroll,
UnrollAndJam,
Distribute,
- Pipeline
+ Pipeline,
+ VectorizePredicate
} Category;
switch (Option) {
case LoopHintAttr::Vectorize:
@@ -232,6 +231,9 @@ CheckForIncompatibleAttributes(Sema &S,
case LoopHintAttr::PipelineInitiationInterval:
Category = Pipeline;
break;
+ case LoopHintAttr::VectorizePredicate:
+ Category = VectorizePredicate;
+ break;
};
assert(Category < sizeof(HintAttrs) / sizeof(HintAttrs[0]));
@@ -240,6 +242,7 @@ CheckForIncompatibleAttributes(Sema &S,
if (Option == LoopHintAttr::Vectorize ||
Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll ||
Option == LoopHintAttr::UnrollAndJam ||
+ Option == LoopHintAttr::VectorizePredicate ||
Option == LoopHintAttr::PipelineDisabled ||
Option == LoopHintAttr::Distribute) {
// Enable|Disable|AssumeSafety hint. For example, vectorize(enable).
@@ -322,7 +325,7 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
S.Diag(A.getLoc(), A.isDeclspecAttribute()
? (unsigned)diag::warn_unhandled_ms_attribute_ignored
: (unsigned)diag::warn_unknown_attribute_ignored)
- << A.getName();
+ << A;
return nullptr;
case ParsedAttr::AT_FallThrough:
return handleFallThroughAttr(S, St, A, Range);
@@ -336,7 +339,7 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
// if we're here, then we parsed a known attribute, but didn't recognize
// it as a statement attribute => it is declaration attribute
S.Diag(A.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt)
- << A.getName() << St->getBeginLoc();
+ << A << St->getBeginLoc();
return nullptr;
}
}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 3212281cc34d..3f2d38630c36 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -20,9 +20,11 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/Stack.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Overload.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaInternal.h"
@@ -44,27 +46,7 @@ clang::getTemplateParamsRange(TemplateParameterList const * const *Ps,
return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc());
}
-namespace clang {
-/// [temp.constr.decl]p2: A template's associated constraints are
-/// defined as a single constraint-expression derived from the introduced
-/// constraint-expressions [ ... ].
-///
-/// \param Params The template parameter list and optional requires-clause.
-///
-/// \param FD The underlying templated function declaration for a function
-/// template.
-static Expr *formAssociatedConstraints(TemplateParameterList *Params,
- FunctionDecl *FD);
-}
-
-static Expr *clang::formAssociatedConstraints(TemplateParameterList *Params,
- FunctionDecl *FD) {
- // FIXME: Concepts: collect additional introduced constraint-expressions
- assert(!FD && "Cannot collect constraints from function declaration yet.");
- return Params->getRequiresClause();
-}
-
-/// Determine whether the declaration found is acceptable as the name
+/// \brief Determine whether the declaration found is acceptable as the name
/// of a template and, if so, return that template declaration. Otherwise,
/// returns null.
///
@@ -362,13 +344,27 @@ bool Sema::LookupTemplateName(LookupResult &Found,
// x->B::f, and we are looking into the type of the object.
assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
LookupCtx = computeDeclContext(ObjectType);
- IsDependent = !LookupCtx;
+ IsDependent = !LookupCtx && ObjectType->isDependentType();
assert((IsDependent || !ObjectType->isIncompleteType() ||
ObjectType->castAs<TagType>()->isBeingDefined()) &&
"Caller should have completed object type");
- // Template names cannot appear inside an Objective-C class or object type.
- if (ObjectType->isObjCObjectOrInterfaceType()) {
+ // Template names cannot appear inside an Objective-C class or object type
+ // or a vector type.
+ //
+ // FIXME: This is wrong. For example:
+ //
+ // template<typename T> using Vec = T __attribute__((ext_vector_type(4)));
+ // Vec<int> vi;
+ // vi.Vec<int>::~Vec<int>();
+ //
+ // ... should be accepted but we will not treat 'Vec' as a template name
+ // here. The right thing to do would be to check if the name is a valid
+ // vector component name, and look up a template name if not. And similarly
+ // for lookups into Objective-C class and object types, where the same
+ // problem can arise.
+ if (ObjectType->isObjCObjectOrInterfaceType() ||
+ ObjectType->isVectorType()) {
Found.clear();
return false;
}
@@ -630,7 +626,7 @@ void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName,
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<TemplateCandidateFilter>(*this);
+ return std::make_unique<TemplateCandidateFilter>(*this);
}
};
@@ -720,9 +716,13 @@ Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
+ // DependentScopeDeclRefExpr::Create requires a valid QualifierLoc
+ NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
+ if (!QualifierLoc)
+ return ExprError();
+
return DependentScopeDeclRefExpr::Create(
- Context, SS.getWithLocInContext(Context), TemplateKWLoc, NameInfo,
- TemplateArgs);
+ Context, QualifierLoc, TemplateKWLoc, NameInfo, TemplateArgs);
}
@@ -830,15 +830,14 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) {
assert(PrevDecl->isTemplateParameter() && "Not a template parameter");
- // Microsoft Visual C++ permits template parameters to be shadowed.
- if (getLangOpts().MicrosoftExt)
- return;
-
// C++ [temp.local]p4:
// A template-parameter shall not be redeclared within its
// scope (including nested scopes).
- Diag(Loc, diag::err_template_param_shadow)
- << cast<NamedDecl>(PrevDecl)->getDeclName();
+ //
+ // Make this a warning when MSVC compatibility is requested.
+ unsigned DiagId = getLangOpts().MSVCCompat ? diag::ext_template_param_shadow
+ : diag::err_template_param_shadow;
+ Diag(Loc, DiagId) << cast<NamedDecl>(PrevDecl)->getDeclName();
Diag(PrevDecl->getLocation(), diag::note_template_param_here);
}
@@ -987,17 +986,16 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
assert(S->isTemplateParamScope() &&
"Template type parameter not in template parameter scope!");
- SourceLocation Loc = ParamNameLoc;
- if (!ParamName)
- Loc = KeyLoc;
-
bool IsParameterPack = EllipsisLoc.isValid();
- TemplateTypeParmDecl *Param
- = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(),
- KeyLoc, Loc, Depth, Position, ParamName,
- Typename, IsParameterPack);
+ TemplateTypeParmDecl *Param = TemplateTypeParmDecl::Create(
+ Context, Context.getTranslationUnitDecl(), KeyLoc, ParamNameLoc, Depth,
+ Position, ParamName, Typename, IsParameterPack);
Param->setAccess(AS_public);
+ if (Param->isParameterPack())
+ if (auto *LSI = getEnclosingLambda())
+ LSI->LocalPacks.push_back(Param);
+
if (ParamName) {
maybeDiagnoseTemplateParameterShadow(*this, S, ParamNameLoc, ParamName);
@@ -1022,7 +1020,7 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
assert(DefaultTInfo && "expected source information for type");
// Check for unexpanded parameter packs.
- if (DiagnoseUnexpandedParameterPack(Loc, DefaultTInfo,
+ if (DiagnoseUnexpandedParameterPack(ParamNameLoc, DefaultTInfo,
UPPC_DefaultArgument))
return Param;
@@ -1082,9 +1080,6 @@ QualType Sema::CheckNonTypeTemplateParameterType(QualType T,
T->isMemberPointerType() ||
// -- std::nullptr_t.
T->isNullPtrType() ||
- // If T is a dependent type, we can't do the check now, so we
- // assume that it is well-formed.
- T->isDependentType() ||
// Allow use of auto in template parameter declarations.
T->isUndeducedType()) {
// C++ [temp.param]p5: The top-level cv-qualifiers on the template-parameter
@@ -1097,9 +1092,18 @@ QualType Sema::CheckNonTypeTemplateParameterType(QualType T,
// A non-type template-parameter of type "array of T" or
// "function returning T" is adjusted to be of type "pointer to
// T" or "pointer to function returning T", respectively.
- else if (T->isArrayType() || T->isFunctionType())
+ if (T->isArrayType() || T->isFunctionType())
return Context.getDecayedType(T);
+ // If T is a dependent type, we can't do the check now, so we
+ // assume that it is well-formed. Note that stripping off the
+ // qualifiers here is not really correct if T turns out to be
+ // an array type, but we'll recompute the type everywhere it's
+ // used during instantiation, so that should be OK. (Using the
+ // qualified type is equally wrong.)
+ if (T->isDependentType())
+ return T.getUnqualifiedType();
+
Diag(Loc, diag::err_template_nontype_parm_bad_type)
<< T;
@@ -1196,6 +1200,10 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
if (Invalid)
Param->setInvalidDecl();
+ if (Param->isParameterPack())
+ if (auto *LSI = getEnclosingLambda())
+ LSI->LocalPacks.push_back(Param);
+
if (ParamName) {
maybeDiagnoseTemplateParameterShadow(*this, S, D.getIdentifierLoc(),
ParamName);
@@ -1259,6 +1267,10 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(Scope* S,
Name, Params);
Param->setAccess(AS_public);
+ if (Param->isParameterPack())
+ if (auto *LSI = getEnclosingLambda())
+ LSI->LocalPacks.push_back(Param);
+
// If the template template parameter has a name, then link the identifier
// into the scope and lookup mechanisms.
if (Name) {
@@ -1502,9 +1514,6 @@ DeclResult Sema::CheckClassTemplate(
}
}
- // TODO Memory management; associated constraints are not always stored.
- Expr *const CurAC = formAssociatedConstraints(TemplateParams, nullptr);
-
if (PrevClassTemplate) {
// Ensure that the template parameter lists are compatible. Skip this check
// for a friend in a dependent context: the template parameter list itself
@@ -1516,30 +1525,6 @@ DeclResult Sema::CheckClassTemplate(
TPL_TemplateMatch))
return true;
- // Check for matching associated constraints on redeclarations.
- const Expr *const PrevAC = PrevClassTemplate->getAssociatedConstraints();
- const bool RedeclACMismatch = [&] {
- if (!(CurAC || PrevAC))
- return false; // Nothing to check; no mismatch.
- if (CurAC && PrevAC) {
- llvm::FoldingSetNodeID CurACInfo, PrevACInfo;
- CurAC->Profile(CurACInfo, Context, /*Canonical=*/true);
- PrevAC->Profile(PrevACInfo, Context, /*Canonical=*/true);
- if (CurACInfo == PrevACInfo)
- return false; // All good; no mismatch.
- }
- return true;
- }();
-
- if (RedeclACMismatch) {
- Diag(CurAC ? CurAC->getBeginLoc() : NameLoc,
- diag::err_template_different_associated_constraints);
- Diag(PrevAC ? PrevAC->getBeginLoc() : PrevClassTemplate->getLocation(),
- diag::note_template_prev_declaration)
- << /*declaration*/ 0;
- return true;
- }
-
// C++ [temp.class]p4:
// In a redeclaration, partial specialization, explicit
// specialization or explicit instantiation of a class template,
@@ -1643,15 +1628,10 @@ DeclResult Sema::CheckClassTemplate(
AddMsStructLayoutForRecord(NewClass);
}
- // Attach the associated constraints when the declaration will not be part of
- // a decl chain.
- Expr *const ACtoAttach =
- PrevClassTemplate && ShouldAddRedecl ? nullptr : CurAC;
-
ClassTemplateDecl *NewTemplate
= ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
DeclarationName(Name), TemplateParams,
- NewClass, ACtoAttach);
+ NewClass);
if (ShouldAddRedecl)
NewTemplate->setPreviousDecl(PrevClassTemplate);
@@ -1690,6 +1670,7 @@ DeclResult Sema::CheckClassTemplate(
mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
AddPushedVisibilityAttribute(NewClass);
+ inferGslOwnerPointerAttribute(NewClass);
if (TUK != TUK_Friend) {
// Per C++ [basic.scope.temp]p2, skip the template parameter scopes.
@@ -3440,7 +3421,7 @@ bool Sema::resolveAssumedTemplateNameAsType(Scope *S, TemplateName &Name,
getAsTypeTemplateDecl(TC.getCorrectionDecl());
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<CandidateCallback>(*this);
+ return std::make_unique<CandidateCallback>(*this);
}
} FilterCCC;
@@ -4239,14 +4220,47 @@ void Sema::diagnoseMissingTemplateArguments(TemplateName Name,
ExprResult
Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
- const DeclarationNameInfo &NameInfo,
- ConceptDecl *Template,
- SourceLocation TemplateLoc,
+ SourceLocation TemplateKWLoc,
+ SourceLocation ConceptNameLoc,
+ NamedDecl *FoundDecl,
+ ConceptDecl *NamedConcept,
const TemplateArgumentListInfo *TemplateArgs) {
- // TODO: Do concept specialization here.
- Diag(NameInfo.getBeginLoc(), diag::err_concept_not_implemented) <<
- "concept specialization";
- return ExprError();
+ assert(NamedConcept && "A concept template id without a template?");
+
+ llvm::SmallVector<TemplateArgument, 4> Converted;
+ if (CheckTemplateArgumentList(NamedConcept, ConceptNameLoc,
+ const_cast<TemplateArgumentListInfo&>(*TemplateArgs),
+ /*PartialTemplateArgs=*/false, Converted,
+ /*UpdateArgsWithConversion=*/false))
+ return ExprError();
+
+ Optional<bool> IsSatisfied;
+ bool AreArgsDependent = false;
+ for (TemplateArgument &Arg : Converted) {
+ if (Arg.isDependent()) {
+ AreArgsDependent = true;
+ break;
+ }
+ }
+ if (!AreArgsDependent) {
+ InstantiatingTemplate Inst(*this, ConceptNameLoc,
+ InstantiatingTemplate::ConstraintsCheck{}, NamedConcept, Converted,
+ SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameLoc,
+ TemplateArgs->getRAngleLoc()));
+ MultiLevelTemplateArgumentList MLTAL;
+ MLTAL.addOuterTemplateArguments(Converted);
+ bool Satisfied;
+ if (CalculateConstraintSatisfaction(NamedConcept, MLTAL,
+ NamedConcept->getConstraintExpr(),
+ Satisfied))
+ return ExprError();
+ IsSatisfied = Satisfied;
+ }
+ return ConceptSpecializationExpr::Create(Context,
+ SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{},
+ TemplateKWLoc, ConceptNameLoc, FoundDecl, NamedConcept,
+ ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), Converted,
+ IsSatisfied);
}
ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
@@ -4289,10 +4303,11 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
TemplateKWLoc, TemplateArgs);
}
- if (R.getAsSingle<ConceptDecl>() && !AnyDependentArguments()) {
- return CheckConceptTemplateId(SS, R.getLookupNameInfo(),
- R.getAsSingle<ConceptDecl>(),
- TemplateKWLoc, TemplateArgs);
+ if (R.getAsSingle<ConceptDecl>()) {
+ return CheckConceptTemplateId(SS, TemplateKWLoc,
+ R.getLookupNameInfo().getBeginLoc(),
+ R.getFoundDecl(),
+ R.getAsSingle<ConceptDecl>(), TemplateArgs);
}
// We don't want lookup warnings at this point.
@@ -4678,6 +4693,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
TemplateArgLists.addOuterTemplateArguments(None);
+ Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
EnterExpressionEvaluationContext ConstantEvaluated(
SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
return SemaRef.SubstExpr(Param->getDefaultArgument(), TemplateArgLists);
@@ -4895,9 +4911,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
if (NTTP->isParameterPack() && NTTP->isExpandedParameterPack())
NTTPType = NTTP->getExpansionType(ArgumentPackIndex);
- // FIXME: Do we need to substitute into parameters here if they're
- // instantiation-dependent but not dependent?
- if (NTTPType->isDependentType() &&
+ if (NTTPType->isInstantiationDependentType() &&
!isa<TemplateTemplateParmDecl>(Template) &&
!Template->getDeclContext()->isDependentContext()) {
// Do substitution on the type of the non-type template parameter.
@@ -5471,7 +5485,7 @@ namespace {
bool Visit##Class##Type(const Class##Type *) { return false; }
#define NON_CANONICAL_TYPE(Class, Parent) \
bool Visit##Class##Type(const Class##Type *) { return false; }
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
bool VisitTagDecl(const TagDecl *Tag);
bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS);
@@ -5847,7 +5861,7 @@ static bool CheckTemplateArgumentIsCompatibleWithParameter(
Expr *Arg, QualType ArgType) {
bool ObjCLifetimeConversion;
if (ParamType->isPointerType() &&
- !ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType() &&
+ !ParamType->castAs<PointerType>()->getPointeeType()->isFunctionType() &&
S.IsQualificationConversion(ArgType, ParamType, false,
ObjCLifetimeConversion)) {
// For pointer-to-object types, qualification conversions are
@@ -6399,8 +6413,11 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
// If either the parameter has a dependent type or the argument is
- // type-dependent, there's nothing we can check now.
- if (ParamType->isDependentType() || Arg->isTypeDependent()) {
+ // type-dependent, there's nothing we can check now. The argument only
+ // contains an unexpanded pack during partial ordering, and there's
+ // nothing more we can check in that case.
+ if (ParamType->isDependentType() || Arg->isTypeDependent() ||
+ Arg->containsUnexpandedParameterPack()) {
// Force the argument to the type of the parameter to maintain invariants.
auto *PE = dyn_cast<PackExpansionExpr>(Arg);
if (PE)
@@ -6720,20 +6737,20 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// overloaded functions (or a pointer to such), the matching
// function is selected from the set (13.4).
(ParamType->isPointerType() &&
- ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType()) ||
+ ParamType->castAs<PointerType>()->getPointeeType()->isFunctionType()) ||
// -- For a non-type template-parameter of type reference to
// function, no conversions apply. If the template-argument
// represents a set of overloaded functions, the matching
// function is selected from the set (13.4).
(ParamType->isReferenceType() &&
- ParamType->getAs<ReferenceType>()->getPointeeType()->isFunctionType()) ||
+ ParamType->castAs<ReferenceType>()->getPointeeType()->isFunctionType()) ||
// -- For a non-type template-parameter of type pointer to
// member function, no conversions apply. If the
// template-argument represents a set of overloaded member
// functions, the matching member function is selected from
// the set (13.4).
(ParamType->isMemberPointerType() &&
- ParamType->getAs<MemberPointerType>()->getPointeeType()
+ ParamType->castAs<MemberPointerType>()->getPointeeType()
->isFunctionType())) {
if (Arg->getType() == Context.OverloadTy) {
@@ -7198,6 +7215,9 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
TemplateArgLoc);
}
+ // TODO: Concepts: Match immediately-introduced-constraint for type
+ // constraints
+
return true;
}
@@ -7223,6 +7243,15 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S,
<< SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc());
}
+static void
+DiagnoseTemplateParameterListRequiresClauseMismatch(Sema &S,
+ TemplateParameterList *New,
+ TemplateParameterList *Old){
+ S.Diag(New->getTemplateLoc(), diag::err_template_different_requires_clause);
+ S.Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration)
+ << /*declaration*/0;
+}
+
/// Determine whether the given template parameter lists are
/// equivalent.
///
@@ -7312,6 +7341,27 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
return false;
}
+ if (Kind != TPL_TemplateTemplateArgumentMatch) {
+ const Expr *NewRC = New->getRequiresClause();
+ const Expr *OldRC = Old->getRequiresClause();
+ if (!NewRC != !OldRC) {
+ if (Complain)
+ DiagnoseTemplateParameterListRequiresClauseMismatch(*this, New, Old);
+ return false;
+ }
+
+ if (NewRC) {
+ llvm::FoldingSetNodeID OldRCID, NewRCID;
+ OldRC->Profile(OldRCID, Context, /*Canonical=*/true);
+ NewRC->Profile(NewRCID, Context, /*Canonical=*/true);
+ if (OldRCID != NewRCID) {
+ if (Complain)
+ DiagnoseTemplateParameterListRequiresClauseMismatch(*this, New, Old);
+ return false;
+ }
+ }
+ }
+
return true;
}
@@ -8020,24 +8070,10 @@ Decl *Sema::ActOnConceptDefinition(Scope *S,
ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, NameLoc, Name,
TemplateParameterLists.front(),
ConstraintExpr);
-
- if (!ConstraintExpr->isTypeDependent() &&
- ConstraintExpr->getType() != Context.BoolTy) {
- // C++2a [temp.constr.atomic]p3:
- // E shall be a constant expression of type bool.
- // TODO: Do this check for individual atomic constraints
- // and not the constraint expression. Probably should do it in
- // ParseConstraintExpression.
- Diag(ConstraintExpr->getSourceRange().getBegin(),
- diag::err_concept_initialized_with_non_bool_type)
- << ConstraintExpr->getType();
- NewDecl->setInvalidDecl();
- }
-
- if (NewDecl->getAssociatedConstraints()) {
+
+ if (NewDecl->hasAssociatedConstraints()) {
// C++2a [temp.concept]p4:
// A concept shall not have associated constraints.
- // TODO: Make a test once we have actual associated constraints.
Diag(NameLoc, diag::err_concept_no_associated_constraints);
NewDecl->setInvalidDecl();
}
@@ -8453,7 +8489,7 @@ bool Sema::CheckFunctionTemplateSpecialization(
// candidates at once, to get proper sorting and limiting.
for (auto *OldND : Previous) {
if (auto *OldFD = dyn_cast<FunctionDecl>(OldND->getUnderlyingDecl()))
- NoteOverloadCandidate(OldND, OldFD, FD->getType(), false);
+ NoteOverloadCandidate(OldND, OldFD, CRK_None, FD->getType(), false);
}
FailedCandidates.NoteCandidates(*this, FD->getLocation());
return true;
@@ -10282,7 +10318,7 @@ void Sema::MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD,
if (!FD)
return;
- auto LPT = llvm::make_unique<LateParsedTemplate>();
+ auto LPT = std::make_unique<LateParsedTemplate>();
// Take tokens to avoid allocations
LPT->Toks.swap(Toks);
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index b55a232d26c2..64ef819e30d4 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -1486,7 +1486,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
#define NON_CANONICAL_TYPE(Class, Base) \
case Type::Class: llvm_unreachable("deducing non-canonical type: " #Class);
#define TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
case Type::TemplateTypeParm:
case Type::SubstTemplateTypeParmPack:
@@ -3093,6 +3093,13 @@ Sema::SubstituteExplicitTemplateArguments(
Function->getTypeSpecStartLoc(), Function->getDeclName());
if (ResultType.isNull() || Trap.hasErrorOccurred())
return TDK_SubstitutionFailure;
+ // CUDA: Kernel function must have 'void' return type.
+ if (getLangOpts().CUDA)
+ if (Function->hasAttr<CUDAGlobalAttr>() && !ResultType->isVoidType()) {
+ Diag(Function->getLocation(), diag::err_kern_type_not_void_return)
+ << Function->getType() << Function->getSourceRange();
+ return TDK_SubstitutionFailure;
+ }
}
// Instantiate the types of each of the function parameters given the
@@ -3702,6 +3709,12 @@ static Sema::TemplateDeductionResult DeduceFromInitializerList(
return Sema::TDK_Success;
}
+ // Resolving a core issue: a braced-init-list containing any designators is
+ // a non-deduced context.
+ for (Expr *E : ILE->inits())
+ if (isa<DesignatedInitExpr>(E))
+ return Sema::TDK_Success;
+
// Deduction only needs to be done for dependent types.
if (ElTy->isDependentType()) {
for (Expr *E : ILE->inits()) {
@@ -3813,8 +3826,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
if (Args.size() < Function->getMinRequiredArguments() && !PartialOverloading)
return TDK_TooFewArguments;
else if (TooManyArguments(NumParams, Args.size(), PartialOverloading)) {
- const FunctionProtoType *Proto
- = Function->getType()->getAs<FunctionProtoType>();
+ const auto *Proto = Function->getType()->castAs<FunctionProtoType>();
if (Proto->isTemplateVariadic())
/* Do nothing */;
else if (!Proto->isVariadic())
@@ -3952,11 +3964,8 @@ QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType,
if (ArgFunctionType.isNull())
return ArgFunctionType;
- const FunctionProtoType *FunctionTypeP =
- FunctionType->castAs<FunctionProtoType>();
- const FunctionProtoType *ArgFunctionTypeP =
- ArgFunctionType->getAs<FunctionProtoType>();
-
+ const auto *FunctionTypeP = FunctionType->castAs<FunctionProtoType>();
+ const auto *ArgFunctionTypeP = ArgFunctionType->castAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = ArgFunctionTypeP->getExtProtoInfo();
bool Rebuild = false;
@@ -4509,6 +4518,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
if (!Type.getType().getNonReferenceType()->getAs<AutoType>())
return DAR_Failed;
+ // Resolving a core issue: a braced-init-list containing any designators is
+ // a non-deduced context.
+ for (Expr *E : InitList->inits())
+ if (isa<DesignatedInitExpr>(E))
+ return DAR_Failed;
+
SourceRange DeducedFromInitRange;
for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
Expr *Init = InitList->getInit(i);
@@ -4632,8 +4647,11 @@ bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
// We might need to deduce the return type by instantiating the definition
// of the operator() function.
- if (CallOp->getReturnType()->isUndeducedType())
- InstantiateFunctionDefinition(Loc, CallOp);
+ if (CallOp->getReturnType()->isUndeducedType()) {
+ runWithSufficientStackSpace(Loc, [&] {
+ InstantiateFunctionDefinition(Loc, CallOp);
+ });
+ }
}
if (CallOp->isInvalidDecl())
@@ -4654,8 +4672,11 @@ bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
return false;
}
- if (FD->getTemplateInstantiationPattern())
- InstantiateFunctionDefinition(Loc, FD);
+ if (FD->getTemplateInstantiationPattern()) {
+ runWithSufficientStackSpace(Loc, [&] {
+ InstantiateFunctionDefinition(Loc, FD);
+ });
+ }
bool StillUndeduced = FD->getReturnType()->isUndeducedType();
if (StillUndeduced && Diagnose && !FD->isInvalidDecl()) {
@@ -5590,7 +5611,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
#define ABSTRACT_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base)
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
break;
}
}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 973f564d3058..0daa33cfbef5 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/PrettyDeclStackTrace.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/Stack.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
@@ -197,12 +198,15 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
case ExplicitTemplateArgumentSubstitution:
case DeducedTemplateArgumentSubstitution:
case PriorTemplateArgumentSubstitution:
+ case ConstraintsCheck:
return true;
case DefaultTemplateArgumentChecking:
case DeclaringSpecialMember:
case DefiningSynthesizedFunction:
case ExceptionSpecEvaluation:
+ case ConstraintSubstitution:
+ case RewritingOperatorAsSpaceship:
return false;
// This function should never be called when Kind's value is Memoization.
@@ -357,6 +361,24 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
PointOfInstantiation, InstantiationRange, Param, Template,
TemplateArgs) {}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ ConstraintsCheck, TemplateDecl *Template,
+ ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, CodeSynthesisContext::ConstraintsCheck,
+ PointOfInstantiation, InstantiationRange, Template, nullptr,
+ TemplateArgs) {}
+
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ ConstraintSubstitution, TemplateDecl *Template,
+ sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, CodeSynthesisContext::ConstraintSubstitution,
+ PointOfInstantiation, InstantiationRange, Template, nullptr,
+ {}, &DeductionInfo) {}
+
void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext;
InNonInstantiationSFINAEContext = false;
@@ -365,6 +387,11 @@ void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
if (!Ctx.isInstantiationRecord())
++NonInstantiationEntries;
+
+ // Check to see if we're low on stack space. We can't do anything about this
+ // from here, but we can at least warn the user.
+ if (isStackNearlyExhausted())
+ warnStackExhausted(Ctx.PointOfInstantiation);
}
void Sema::popCodeSynthesisContext() {
@@ -656,8 +683,37 @@ void Sema::PrintInstantiationStack() {
break;
}
+ case CodeSynthesisContext::RewritingOperatorAsSpaceship:
+ Diags.Report(Active->Entity->getLocation(),
+ diag::note_rewriting_operator_as_spaceship);
+ break;
+
case CodeSynthesisContext::Memoization:
break;
+
+ case CodeSynthesisContext::ConstraintsCheck:
+ if (auto *CD = dyn_cast<ConceptDecl>(Active->Entity)) {
+ SmallVector<char, 128> TemplateArgsStr;
+ llvm::raw_svector_ostream OS(TemplateArgsStr);
+ CD->printName(OS);
+ printTemplateArgumentList(OS, Active->template_arguments(),
+ getPrintingPolicy());
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_concept_specialization_here)
+ << OS.str()
+ << Active->InstantiationRange;
+ break;
+ }
+ // TODO: Concepts - implement this for constrained templates and partial
+ // specializations.
+ llvm_unreachable("only concept constraints are supported right now");
+ break;
+
+ case CodeSynthesisContext::ConstraintSubstitution:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_constraint_substitution_here)
+ << Active->InstantiationRange;
+ break;
}
}
}
@@ -681,6 +737,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
LLVM_FALLTHROUGH;
case CodeSynthesisContext::DefaultFunctionArgumentInstantiation:
case CodeSynthesisContext::ExceptionSpecInstantiation:
+ case CodeSynthesisContext::ConstraintsCheck:
// This is a template instantiation, so there is no SFINAE.
return None;
@@ -694,13 +751,16 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution:
case CodeSynthesisContext::DeducedTemplateArgumentSubstitution:
- // We're either substitution explicitly-specified template arguments
- // or deduced template arguments, so SFINAE applies.
+ case CodeSynthesisContext::ConstraintSubstitution:
+ // We're either substituting explicitly-specified template arguments
+ // or deduced template arguments or a constraint expression, so SFINAE
+ // applies.
assert(Active->DeductionInfo && "Missing deduction info pointer");
return Active->DeductionInfo;
case CodeSynthesisContext::DeclaringSpecialMember:
case CodeSynthesisContext::DefiningSynthesizedFunction:
+ case CodeSynthesisContext::RewritingOperatorAsSpaceship:
// This happens in a context unrelated to template instantiation, so
// there is no SFINAE.
return None;
@@ -1252,9 +1312,8 @@ TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) {
// Create new LoopHintValueAttr with integral expression in place of the
// non-type template parameter.
- return LoopHintAttr::CreateImplicit(
- getSema().Context, LH->getSemanticSpelling(), LH->getOption(),
- LH->getState(), TransformedExpr, LH->getRange());
+ return LoopHintAttr::CreateImplicit(getSema().Context, LH->getOption(),
+ LH->getState(), TransformedExpr, *LH);
}
ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 67343d11d333..d1ad304e62e4 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -86,15 +86,13 @@ static void instantiateDependentAlignedAttr(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Result = S.SubstExpr(Aligned->getAlignmentExpr(), TemplateArgs);
if (!Result.isInvalid())
- S.AddAlignedAttr(Aligned->getLocation(), New, Result.getAs<Expr>(),
- Aligned->getSpellingListIndex(), IsPackExpansion);
+ S.AddAlignedAttr(New, *Aligned, Result.getAs<Expr>(), IsPackExpansion);
} else {
TypeSourceInfo *Result = S.SubstType(Aligned->getAlignmentType(),
TemplateArgs, Aligned->getLocation(),
DeclarationName());
if (Result)
- S.AddAlignedAttr(Aligned->getLocation(), New, Result,
- Aligned->getSpellingListIndex(), IsPackExpansion);
+ S.AddAlignedAttr(New, *Aligned, Result, IsPackExpansion);
}
}
@@ -156,8 +154,7 @@ static void instantiateDependentAssumeAlignedAttr(
OE = Result.getAs<Expr>();
}
- S.AddAssumeAlignedAttr(Aligned->getLocation(), New, E, OE,
- Aligned->getSpellingListIndex());
+ S.AddAssumeAlignedAttr(New, *Aligned, E, OE);
}
static void instantiateDependentAlignValueAttr(
@@ -168,8 +165,7 @@ static void instantiateDependentAlignValueAttr(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Result = S.SubstExpr(Aligned->getAlignment(), TemplateArgs);
if (!Result.isInvalid())
- S.AddAlignValueAttr(Aligned->getLocation(), New, Result.getAs<Expr>(),
- Aligned->getSpellingListIndex());
+ S.AddAlignValueAttr(New, *Aligned, Result.getAs<Expr>());
}
static void instantiateDependentAllocAlignAttr(
@@ -179,8 +175,7 @@ static void instantiateDependentAllocAlignAttr(
S.getASTContext(),
llvm::APInt(64, Align->getParamIndex().getSourceIndex()),
S.getASTContext().UnsignedLongLongTy, Align->getLocation());
- S.AddAllocAlignAttr(Align->getLocation(), New, Param,
- Align->getSpellingListIndex());
+ S.AddAllocAlignAttr(New, *Align, Param);
}
static Expr *instantiateDependentFunctionAttrCondition(
@@ -221,9 +216,8 @@ static void instantiateDependentEnableIfAttr(
S, TemplateArgs, EIA, EIA->getCond(), Tmpl, New);
if (Cond)
- New->addAttr(new (S.getASTContext()) EnableIfAttr(
- EIA->getLocation(), S.getASTContext(), Cond, EIA->getMessage(),
- EIA->getSpellingListIndex()));
+ New->addAttr(new (S.getASTContext()) EnableIfAttr(S.getASTContext(), *EIA,
+ Cond, EIA->getMessage()));
}
static void instantiateDependentDiagnoseIfAttr(
@@ -234,9 +228,8 @@ static void instantiateDependentDiagnoseIfAttr(
if (Cond)
New->addAttr(new (S.getASTContext()) DiagnoseIfAttr(
- DIA->getLocation(), S.getASTContext(), Cond, DIA->getMessage(),
- DIA->getDiagnosticType(), DIA->getArgDependent(), New,
- DIA->getSpellingListIndex()));
+ S.getASTContext(), *DIA, Cond, DIA->getMessage(),
+ DIA->getDiagnosticType(), DIA->getArgDependent(), New));
}
// Constructs and adds to New a new instance of CUDALaunchBoundsAttr using
@@ -261,16 +254,15 @@ static void instantiateDependentCUDALaunchBoundsAttr(
MinBlocks = Result.getAs<Expr>();
}
- S.AddLaunchBoundsAttr(Attr.getLocation(), New, MaxThreads, MinBlocks,
- Attr.getSpellingListIndex());
+ S.AddLaunchBoundsAttr(New, Attr, MaxThreads, MinBlocks);
}
static void
instantiateDependentModeAttr(Sema &S,
const MultiLevelTemplateArgumentList &TemplateArgs,
const ModeAttr &Attr, Decl *New) {
- S.AddModeAttr(Attr.getRange(), New, Attr.getMode(),
- Attr.getSpellingListIndex(), /*InInstantiation=*/true);
+ S.AddModeAttr(New, Attr, Attr.getMode(),
+ /*InInstantiation=*/true);
}
/// Instantiation of 'declare simd' attribute and its arguments.
@@ -356,6 +348,67 @@ static void instantiateOMPDeclareSimdDeclAttr(
Attr.getRange());
}
+/// Instantiation of 'declare variant' attribute and its arguments.
+static void instantiateOMPDeclareVariantAttr(
+ Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
+ const OMPDeclareVariantAttr &Attr, Decl *New) {
+ // Allow 'this' in clauses with varlists.
+ if (auto *FTD = dyn_cast<FunctionTemplateDecl>(New))
+ New = FTD->getTemplatedDecl();
+ auto *FD = cast<FunctionDecl>(New);
+ auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(FD->getDeclContext());
+
+ auto &&SubstExpr = [FD, ThisContext, &S, &TemplateArgs](Expr *E) {
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
+ if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
+ Sema::ContextRAII SavedContext(S, FD);
+ LocalInstantiationScope Local(S);
+ if (FD->getNumParams() > PVD->getFunctionScopeIndex())
+ Local.InstantiatedLocal(
+ PVD, FD->getParamDecl(PVD->getFunctionScopeIndex()));
+ return S.SubstExpr(E, TemplateArgs);
+ }
+ Sema::CXXThisScopeRAII ThisScope(S, ThisContext, Qualifiers(),
+ FD->isCXXInstanceMember());
+ return S.SubstExpr(E, TemplateArgs);
+ };
+
+ // Substitute a single OpenMP clause, which is a potentially-evaluated
+ // full-expression.
+ auto &&Subst = [&SubstExpr, &S](Expr *E) {
+ EnterExpressionEvaluationContext Evaluated(
+ S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
+ ExprResult Res = SubstExpr(E);
+ if (Res.isInvalid())
+ return Res;
+ return S.ActOnFinishFullExpr(Res.get(), false);
+ };
+
+ ExprResult VariantFuncRef;
+ if (Expr *E = Attr.getVariantFuncRef())
+ VariantFuncRef = Subst(E);
+
+ ExprResult Score;
+ if (Expr *E = Attr.getScore())
+ Score = Subst(E);
+
+ // Check function/variant ref.
+ Optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =
+ S.checkOpenMPDeclareVariantFunction(
+ S.ConvertDeclToDeclGroup(New), VariantFuncRef.get(), Attr.getRange());
+ if (!DeclVarData)
+ return;
+ // Instantiate the attribute.
+ Sema::OpenMPDeclareVariantCtsSelectorData Data(
+ Attr.getCtxSelectorSet(), Attr.getCtxSelector(),
+ llvm::makeMutableArrayRef(Attr.implVendors_begin(),
+ Attr.implVendors_size()),
+ Score);
+ S.ActOnOpenMPDeclareVariantDirective(DeclVarData.getValue().first,
+ DeclVarData.getValue().second,
+ Attr.getRange(), Data);
+}
+
static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AMDGPUFlatWorkGroupSizeAttr &Attr, Decl *New) {
@@ -373,8 +426,7 @@ static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
return;
Expr *MaxExpr = Result.getAs<Expr>();
- S.addAMDGPUFlatWorkGroupSizeAttr(Attr.getLocation(), New, MinExpr, MaxExpr,
- Attr.getSpellingListIndex());
+ S.addAMDGPUFlatWorkGroupSizeAttr(New, Attr, MinExpr, MaxExpr);
}
static ExplicitSpecifier
@@ -420,8 +472,7 @@ static void instantiateDependentAMDGPUWavesPerEUAttr(
MaxExpr = Result.getAs<Expr>();
}
- S.addAMDGPUWavesPerEUAttr(Attr.getLocation(), New, MinExpr, MaxExpr,
- Attr.getSpellingListIndex());
+ S.addAMDGPUWavesPerEUAttr(New, Attr, MinExpr, MaxExpr);
}
void Sema::InstantiateAttrsForDecl(
@@ -470,14 +521,12 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}
- const AssumeAlignedAttr *AssumeAligned = dyn_cast<AssumeAlignedAttr>(TmplAttr);
- if (AssumeAligned) {
+ if (const auto *AssumeAligned = dyn_cast<AssumeAlignedAttr>(TmplAttr)) {
instantiateDependentAssumeAlignedAttr(*this, TemplateArgs, AssumeAligned, New);
continue;
}
- const AlignValueAttr *AlignValue = dyn_cast<AlignValueAttr>(TmplAttr);
- if (AlignValue) {
+ if (const auto *AlignValue = dyn_cast<AlignValueAttr>(TmplAttr)) {
instantiateDependentAlignValueAttr(*this, TemplateArgs, AlignValue, New);
continue;
}
@@ -500,14 +549,14 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}
- if (const CUDALaunchBoundsAttr *CUDALaunchBounds =
+ if (const auto *CUDALaunchBounds =
dyn_cast<CUDALaunchBoundsAttr>(TmplAttr)) {
instantiateDependentCUDALaunchBoundsAttr(*this, TemplateArgs,
*CUDALaunchBounds, New);
continue;
}
- if (const ModeAttr *Mode = dyn_cast<ModeAttr>(TmplAttr)) {
+ if (const auto *Mode = dyn_cast<ModeAttr>(TmplAttr)) {
instantiateDependentModeAttr(*this, TemplateArgs, *Mode, New);
continue;
}
@@ -517,13 +566,18 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}
- if (const AMDGPUFlatWorkGroupSizeAttr *AMDGPUFlatWorkGroupSize =
+ if (const auto *OMPAttr = dyn_cast<OMPDeclareVariantAttr>(TmplAttr)) {
+ instantiateOMPDeclareVariantAttr(*this, TemplateArgs, *OMPAttr, New);
+ continue;
+ }
+
+ if (const auto *AMDGPUFlatWorkGroupSize =
dyn_cast<AMDGPUFlatWorkGroupSizeAttr>(TmplAttr)) {
instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
*this, TemplateArgs, *AMDGPUFlatWorkGroupSize, New);
}
- if (const AMDGPUWavesPerEUAttr *AMDGPUFlatWorkGroupSize =
+ if (const auto *AMDGPUFlatWorkGroupSize =
dyn_cast<AMDGPUWavesPerEUAttr>(TmplAttr)) {
instantiateDependentAMDGPUWavesPerEUAttr(*this, TemplateArgs,
*AMDGPUFlatWorkGroupSize, New);
@@ -537,21 +591,30 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
}
}
- if (auto ABIAttr = dyn_cast<ParameterABIAttr>(TmplAttr)) {
- AddParameterABIAttr(ABIAttr->getRange(), New, ABIAttr->getABI(),
- ABIAttr->getSpellingListIndex());
+ if (const auto *ABIAttr = dyn_cast<ParameterABIAttr>(TmplAttr)) {
+ AddParameterABIAttr(New, *ABIAttr, ABIAttr->getABI());
continue;
}
if (isa<NSConsumedAttr>(TmplAttr) || isa<OSConsumedAttr>(TmplAttr) ||
isa<CFConsumedAttr>(TmplAttr)) {
- AddXConsumedAttr(New, TmplAttr->getRange(),
- TmplAttr->getSpellingListIndex(),
- attrToRetainOwnershipKind(TmplAttr),
+ AddXConsumedAttr(New, *TmplAttr, attrToRetainOwnershipKind(TmplAttr),
/*template instantiation=*/true);
continue;
}
+ if (auto *A = dyn_cast<PointerAttr>(TmplAttr)) {
+ if (!New->hasAttr<PointerAttr>())
+ New->addAttr(A->clone(Context));
+ continue;
+ }
+
+ if (auto *A = dyn_cast<OwnerAttr>(TmplAttr)) {
+ if (!New->hasAttr<OwnerAttr>())
+ New->addAttr(A->clone(Context));
+ continue;
+ }
+
assert(!TmplAttr->isPackExpansion());
if (TmplAttr->isLateParsed() && LateAttrs) {
// Late parsed attributes must be instantiated and attached after the
@@ -711,6 +774,9 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef);
+ if (D->getUnderlyingType()->getAs<DependentNameType>())
+ SemaRef.inferGslPointerAttribute(Typedef);
+
Typedef->setAccess(D->getAccess());
return Typedef;
@@ -2090,10 +2156,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
Constructor->getConstexprKind());
Method->setRangeEnd(Constructor->getEndLoc());
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
- Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
- StartLoc, NameInfo, T, TInfo,
- Destructor->isInlineSpecified(),
- false);
+ Method = CXXDestructorDecl::Create(
+ SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
+ Destructor->isInlineSpecified(), false, Destructor->getConstexprKind());
Method->setRangeEnd(Destructor->getEndLoc());
} else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
Method = CXXConversionDecl::Create(
@@ -2339,6 +2404,7 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getIndex(),
D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack());
Inst->setAccess(AS_public);
+ Inst->setImplicit(D->isImplicit());
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
TypeSourceInfo *InstantiatedDefaultArg =
@@ -2485,6 +2551,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI);
Param->setAccess(AS_public);
+ Param->setImplicit(D->isImplicit());
if (Invalid)
Param->setInvalidDecl();
@@ -2628,6 +2695,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
D->getDefaultArgument().getTemplateNameLoc()));
}
Param->setAccess(AS_public);
+ Param->setImplicit(D->isImplicit());
// Introduce this template parameter's instantiation into the instantiation
// scope.
@@ -3415,7 +3483,11 @@ Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
if (D->isInvalidDecl())
return nullptr;
- return Instantiator.Visit(D);
+ Decl *SubstD;
+ runWithSufficientStackSpace(D->getLocation(), [&] {
+ SubstD = Instantiator.Visit(D);
+ });
+ return SubstD;
}
/// Instantiates a nested template parameter list in the current
@@ -3443,14 +3515,21 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
if (Invalid)
return nullptr;
- // Note: we substitute into associated constraints later
- Expr *const UninstantiatedRequiresClause = L->getRequiresClause();
+ // FIXME: Concepts: Substitution into requires clause should only happen when
+ // checking satisfaction.
+ Expr *InstRequiresClause = nullptr;
+ if (Expr *E = L->getRequiresClause()) {
+ ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs);
+ if (Res.isInvalid() || !Res.isUsable()) {
+ return nullptr;
+ }
+ InstRequiresClause = Res.get();
+ }
TemplateParameterList *InstL
= TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(),
L->getLAngleLoc(), Params,
- L->getRAngleLoc(),
- UninstantiatedRequiresClause);
+ L->getRAngleLoc(), InstRequiresClause);
return InstL;
}
@@ -5217,11 +5296,11 @@ DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC,
/// template struct X<int>;
/// \endcode
///
-/// In the instantiation of <tt>X<int>::getKind()</tt>, we need to map the
-/// \p EnumConstantDecl for \p KnownValue (which refers to
-/// <tt>X<T>::<Kind>::KnownValue</tt>) to its instantiation
-/// (<tt>X<int>::<Kind>::KnownValue</tt>). \p FindInstantiatedDecl performs
-/// this mapping from within the instantiation of <tt>X<int></tt>.
+/// In the instantiation of X<int>::getKind(), we need to map the \p
+/// EnumConstantDecl for \p KnownValue (which refers to
+/// X<T>::<Kind>::KnownValue) to its instantiation (X<int>::<Kind>::KnownValue).
+/// \p FindInstantiatedDecl performs this mapping from within the instantiation
+/// of X<int>.
NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs,
bool FindingInstantiatedContext) {
@@ -5312,20 +5391,6 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
return cast<LabelDecl>(Inst);
}
- // For variable template specializations, update those that are still
- // type-dependent.
- if (VarTemplateSpecializationDecl *VarSpec =
- dyn_cast<VarTemplateSpecializationDecl>(D)) {
- bool InstantiationDependent = false;
- const TemplateArgumentListInfo &VarTemplateArgs =
- VarSpec->getTemplateArgsInfo();
- if (TemplateSpecializationType::anyDependentTemplateArguments(
- VarTemplateArgs, InstantiationDependent))
- D = cast<NamedDecl>(
- SubstDecl(D, VarSpec->getDeclContext(), TemplateArgs));
- return D;
- }
-
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
if (!Record->isDependentContext())
return D;
@@ -5450,11 +5515,23 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// find it. Does that ever matter?
if (auto Name = D->getDeclName()) {
DeclarationNameInfo NameInfo(Name, D->getLocation());
- Name = SubstDeclarationNameInfo(NameInfo, TemplateArgs).getName();
+ DeclarationNameInfo NewNameInfo =
+ SubstDeclarationNameInfo(NameInfo, TemplateArgs);
+ Name = NewNameInfo.getName();
if (!Name)
return nullptr;
DeclContext::lookup_result Found = ParentDC->lookup(Name);
- Result = findInstantiationOf(Context, D, Found.begin(), Found.end());
+
+ if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) {
+ VarTemplateDecl *Templ = cast_or_null<VarTemplateDecl>(
+ findInstantiationOf(Context, VTSD->getSpecializedTemplate(),
+ Found.begin(), Found.end()));
+ if (!Templ)
+ return nullptr;
+ Result = getVarTemplateSpecialization(
+ Templ, &VTSD->getTemplateArgsInfo(), NewNameInfo, SourceLocation());
+ } else
+ Result = findInstantiationOf(Context, D, Found.begin(), Found.end());
} else {
// Since we don't have a name for the entity we're looking for,
// our only option is to walk through all of the declarations to
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index d97626551a41..975d6620c06f 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -294,44 +294,58 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
return false;
// If we are within a lambda expression and referencing a pack that is not
- // a parameter of the lambda itself, that lambda contains an unexpanded
+ // declared within the lambda itself, that lambda contains an unexpanded
// parameter pack, and we are done.
// FIXME: Store 'Unexpanded' on the lambda so we don't need to recompute it
// later.
SmallVector<UnexpandedParameterPack, 4> LambdaParamPackReferences;
- for (unsigned N = FunctionScopes.size(); N; --N) {
- sema::FunctionScopeInfo *Func = FunctionScopes[N-1];
- // We do not permit pack expansion that would duplicate a statement
- // expression, not even within a lambda.
- // FIXME: We could probably support this for statement expressions that do
- // not contain labels, and for pack expansions that expand both the stmt
- // expr and the enclosing lambda.
- if (std::any_of(
- Func->CompoundScopes.begin(), Func->CompoundScopes.end(),
- [](sema::CompoundScopeInfo &CSI) { return CSI.IsStmtExpr; }))
- break;
+ if (auto *LSI = getEnclosingLambda()) {
+ for (auto &Pack : Unexpanded) {
+ auto DeclaresThisPack = [&](NamedDecl *LocalPack) {
+ if (auto *TTPT = Pack.first.dyn_cast<const TemplateTypeParmType *>()) {
+ auto *TTPD = dyn_cast<TemplateTypeParmDecl>(LocalPack);
+ return TTPD && TTPD->getTypeForDecl() == TTPT;
+ }
+ return declaresSameEntity(Pack.first.get<NamedDecl *>(), LocalPack);
+ };
+ if (std::find_if(LSI->LocalPacks.begin(), LSI->LocalPacks.end(),
+ DeclaresThisPack) != LSI->LocalPacks.end())
+ LambdaParamPackReferences.push_back(Pack);
+ }
- if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Func)) {
- if (N == FunctionScopes.size()) {
- for (auto &Pack : Unexpanded) {
- auto *VD = dyn_cast_or_null<VarDecl>(
- Pack.first.dyn_cast<NamedDecl *>());
- if (VD && VD->getDeclContext() == LSI->CallOperator)
- LambdaParamPackReferences.push_back(Pack);
+ if (LambdaParamPackReferences.empty()) {
+ // Construct in lambda only references packs declared outside the lambda.
+ // That's OK for now, but the lambda itself is considered to contain an
+ // unexpanded pack in this case, which will require expansion outside the
+ // lambda.
+
+ // We do not permit pack expansion that would duplicate a statement
+ // expression, not even within a lambda.
+ // FIXME: We could probably support this for statement expressions that
+ // do not contain labels.
+ // FIXME: This is insufficient to detect this problem; consider
+ // f( ({ bad: 0; }) + pack ... );
+ bool EnclosingStmtExpr = false;
+ for (unsigned N = FunctionScopes.size(); N; --N) {
+ sema::FunctionScopeInfo *Func = FunctionScopes[N-1];
+ if (std::any_of(
+ Func->CompoundScopes.begin(), Func->CompoundScopes.end(),
+ [](sema::CompoundScopeInfo &CSI) { return CSI.IsStmtExpr; })) {
+ EnclosingStmtExpr = true;
+ break;
}
+ // Coumpound-statements outside the lambda are OK for now; we'll check
+ // for those when we finish handling the lambda.
+ if (Func == LSI)
+ break;
}
- // If we have references to a parameter pack of the innermost enclosing
- // lambda, only diagnose those ones. We don't know whether any other
- // unexpanded parameters referenced herein are actually unexpanded;
- // they might be expanded at an outer level.
- if (!LambdaParamPackReferences.empty()) {
- Unexpanded = LambdaParamPackReferences;
- break;
+ if (!EnclosingStmtExpr) {
+ LSI->ContainsUnexpandedParameterPack = true;
+ return false;
}
-
- LSI->ContainsUnexpandedParameterPack = true;
- return false;
+ } else {
+ Unexpanded = LambdaParamPackReferences;
}
}
@@ -937,7 +951,7 @@ class ParameterPackValidatorCCC final : public CorrectionCandidateCallback {
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<ParameterPackValidatorCCC>(*this);
+ return std::make_unique<ParameterPackValidatorCCC>(*this);
}
};
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 29acf6177eb9..fccdb2bc2e2c 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -82,7 +82,7 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr,
}
SourceLocation loc = attr.getLoc();
- StringRef name = attr.getName()->getName();
+ StringRef name = attr.getAttrName()->getName();
// The GC attributes are usually written with macros; special-case them.
IdentifierInfo *II = attr.isArgIdent(0) ? attr.getArgAsIdent(0)->Ident
@@ -811,7 +811,7 @@ static bool checkOmittedBlockReturnType(Sema &S, Declarator &declarator,
continue;
S.Diag(AL.getLoc(),
diag::warn_block_literal_attributes_on_omitted_return_type)
- << AL.getName();
+ << AL;
ToBeRemoved.push_back(&AL);
}
// Remove bad attributes from the list.
@@ -1290,14 +1290,14 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified)
Result = Context.WCharTy;
else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) {
- S.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec)
+ S.Diag(DS.getTypeSpecSignLoc(), diag::ext_wchar_t_sign_spec)
<< DS.getSpecifierName(DS.getTypeSpecType(),
Context.getPrintingPolicy());
Result = Context.getSignedWCharType();
} else {
assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned &&
"Unknown TSS value");
- S.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec)
+ S.Diag(DS.getTypeSpecSignLoc(), diag::ext_wchar_t_sign_spec)
<< DS.getSpecifierName(DS.getTypeSpecType(),
Context.getPrintingPolicy());
Result = Context.getUnsignedWCharType();
@@ -1633,6 +1633,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
case OpenCLAccessAttr::Keyword_read_only: \
Result = Context.Id##ROTy; \
break; \
+ case OpenCLAccessAttr::SpellingNotCalculated: \
+ llvm_unreachable("Spelling not yet calculated"); \
} \
break;
#include "clang/Basic/OpenCLImageTypes.def"
@@ -1953,7 +1955,8 @@ static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation Loc,
QualifiedFunctionKind QFK) {
// Does T refer to a function type with a cv-qualifier or a ref-qualifier?
const FunctionProtoType *FPT = T->getAs<FunctionProtoType>();
- if (!FPT || (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None))
+ if (!FPT ||
+ (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None))
return false;
S.Diag(Loc, diag::err_compound_qualified_function_type)
@@ -1962,6 +1965,17 @@ static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation Loc,
return true;
}
+bool Sema::CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc) {
+ const FunctionProtoType *FPT = T->getAs<FunctionProtoType>();
+ if (!FPT ||
+ (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None))
+ return false;
+
+ Diag(Loc, diag::err_qualified_function_typeid)
+ << T << getFunctionQualifiersAsString(FPT);
+ return true;
+}
+
/// Build a pointer type.
///
/// \param T The type to which we'll be building a pointer.
@@ -2276,7 +2290,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
}
}
- T = Context.getConstantArrayType(T, ConstVal, ASM, Quals);
+ T = Context.getConstantArrayType(T, ConstVal, ArraySize, ASM, Quals);
}
// OpenCL v1.2 s6.9.d: variable length arrays are not supported.
@@ -2461,6 +2475,11 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) {
checkNonTrivialCUnion(T, Loc, NTCUC_FunctionReturn,
NTCUK_Destruct|NTCUK_Copy);
+ // C++2a [dcl.fct]p12:
+ // A volatile-qualified return type is deprecated
+ if (T.isVolatileQualified() && getLangOpts().CPlusPlus2a)
+ Diag(Loc, diag::warn_deprecated_volatile_return) << T;
+
return false;
}
@@ -2541,6 +2560,11 @@ QualType Sema::BuildFunctionType(QualType T,
Invalid = true;
}
+ // C++2a [dcl.fct]p4:
+ // A parameter with volatile-qualified type is deprecated
+ if (ParamType.isVolatileQualified() && getLangOpts().CPlusPlus2a)
+ Diag(Loc, diag::warn_deprecated_volatile_param) << ParamType;
+
ParamTypes[Idx] = ParamType;
}
@@ -3942,10 +3966,9 @@ static bool IsNoDerefableChunk(DeclaratorChunk Chunk) {
}
template<typename AttrT>
-static AttrT *createSimpleAttr(ASTContext &Ctx, ParsedAttr &Attr) {
- Attr.setUsedAsTypeAttr();
- return ::new (Ctx)
- AttrT(Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex());
+static AttrT *createSimpleAttr(ASTContext &Ctx, ParsedAttr &AL) {
+ AL.setUsedAsTypeAttr();
+ return ::new (Ctx) AttrT(Ctx, AL);
}
static Attr *createNullabilityAttr(ASTContext &Ctx, ParsedAttr &Attr,
@@ -4672,6 +4695,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
S.Diag(DeclType.Loc, diag::err_func_returning_qualified_void) << T;
} else
diagnoseRedundantReturnTypeQualifiers(S, T, D, chunkIndex);
+
+ // C++2a [dcl.fct]p12:
+ // A volatile-qualified return type is deprecated
+ if (T.isVolatileQualified() && S.getLangOpts().CPlusPlus2a)
+ S.Diag(DeclType.Loc, diag::warn_deprecated_volatile_return) << T;
}
// Objective-C ARC ownership qualifiers are ignored on the function
@@ -5151,9 +5179,16 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// C++0x [dcl.constexpr]p9:
// A constexpr specifier used in an object declaration declares the object
// as const.
- if (D.getDeclSpec().hasConstexprSpecifier() && T->isObjectType()) {
+ if (D.getDeclSpec().getConstexprSpecifier() == CSK_constexpr &&
+ T->isObjectType())
T.addConst();
- }
+
+ // C++2a [dcl.fct]p4:
+ // A parameter with volatile-qualified type is deprecated
+ if (T.isVolatileQualified() && S.getLangOpts().CPlusPlus2a &&
+ (D.getContext() == DeclaratorContext::PrototypeContext ||
+ D.getContext() == DeclaratorContext::LambdaExprParameterContext))
+ S.Diag(D.getIdentifierLoc(), diag::warn_deprecated_volatile_param) << T;
// If there was an ellipsis in the declarator, the declaration declares a
// parameter pack whose type may be a pack expansion type.
@@ -5983,9 +6018,8 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
}
ASTContext &Ctx = S.Context;
- auto *ASAttr = ::new (Ctx) AddressSpaceAttr(
- Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex(),
- static_cast<unsigned>(ASIdx));
+ auto *ASAttr =
+ ::new (Ctx) AddressSpaceAttr(Ctx, Attr, static_cast<unsigned>(ASIdx));
// If the expression is not value dependent (not templated), then we can
// apply the address space qualifiers just to the equivalent type.
@@ -6027,36 +6061,6 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
}
}
-/// Does this type have a "direct" ownership qualifier? That is,
-/// is it written like "__strong id", as opposed to something like
-/// "typeof(foo)", where that happens to be strong?
-static bool hasDirectOwnershipQualifier(QualType type) {
- // Fast path: no qualifier at all.
- assert(type.getQualifiers().hasObjCLifetime());
-
- while (true) {
- // __strong id
- if (const AttributedType *attr = dyn_cast<AttributedType>(type)) {
- if (attr->getAttrKind() == attr::ObjCOwnership)
- return true;
-
- type = attr->getModifiedType();
-
- // X *__strong (...)
- } else if (const ParenType *paren = dyn_cast<ParenType>(type)) {
- type = paren->getInnerType();
-
- // That's it for things we want to complain about. In particular,
- // we do not want to look through typedefs, typeof(expr),
- // typeof(type), or any other way that the type is somehow
- // abstracted.
- } else {
-
- return false;
- }
- }
-}
-
/// handleObjCOwnershipTypeAttr - Process an objc_ownership
/// attribute on the specified type.
///
@@ -6112,8 +6116,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
else if (II->isStr("autoreleasing"))
lifetime = Qualifiers::OCL_Autoreleasing;
else {
- S.Diag(AttrLoc, diag::warn_attribute_type_not_supported)
- << attr.getName() << II;
+ S.Diag(AttrLoc, diag::warn_attribute_type_not_supported) << attr << II;
attr.setInvalid();
return true;
}
@@ -6132,7 +6135,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
if (Qualifiers::ObjCLifetime previousLifetime
= type.getQualifiers().getObjCLifetime()) {
// If it's written directly, that's an error.
- if (hasDirectOwnershipQualifier(type)) {
+ if (S.Context.hasDirectOwnershipQualifier(type)) {
S.Diag(AttrLoc, diag::err_attr_objc_ownership_redundant)
<< type;
return true;
@@ -6155,7 +6158,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
underlyingType.Quals.addObjCLifetime(lifetime);
if (NonObjCPointer) {
- StringRef name = attr.getName()->getName();
+ StringRef name = attr.getAttrName()->getName();
switch (lifetime) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
@@ -6194,9 +6197,8 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
// If we have a valid source location for the attribute, use an
// AttributedType instead.
if (AttrLoc.isValid()) {
- type = state.getAttributedType(::new (S.Context) ObjCOwnershipAttr(
- attr.getRange(), S.Context, II,
- attr.getAttributeSpellingListIndex()),
+ type = state.getAttributedType(::new (S.Context)
+ ObjCOwnershipAttr(S.Context, attr, II),
origType, type);
}
@@ -6288,7 +6290,7 @@ static bool handleObjCGCTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
GCAttr = Qualifiers::Strong;
else {
S.Diag(attr.getLoc(), diag::warn_attribute_type_not_supported)
- << attr.getName() << II;
+ << attr << II;
attr.setInvalid();
return true;
}
@@ -6299,9 +6301,7 @@ static bool handleObjCGCTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
// Make an attributed type to preserve the source information.
if (attr.getLoc().isValid())
type = state.getAttributedType(
- ::new (S.Context) ObjCGCAttr(attr.getRange(), S.Context, II,
- attr.getAttributeSpellingListIndex()),
- origType, type);
+ ::new (S.Context) ObjCGCAttr(S.Context, attr, II), origType, type);
return true;
}
@@ -6473,8 +6473,7 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
// You cannot specify duplicate type attributes, so if the attribute has
// already been applied, flag it.
if (NewAttrKind == CurAttrKind) {
- S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact)
- << PAttr.getName();
+ S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr;
return true;
}
@@ -6743,9 +6742,9 @@ static bool distributeNullabilityTypeAttr(TypeProcessingState &state,
if (chunk.Kind != DeclaratorChunk::MemberPointer) {
diag << FixItHint::CreateRemoval(attr.getLoc())
<< FixItHint::CreateInsertion(
- state.getSema().getPreprocessor()
- .getLocForEndOfToken(chunk.Loc),
- " " + attr.getName()->getName().str() + " ");
+ state.getSema().getPreprocessor().getLocForEndOfToken(
+ chunk.Loc),
+ " " + attr.getAttrName()->getName().str() + " ");
}
moveAttrFromListToList(attr, state.getCurrentAttributes(),
@@ -6823,8 +6822,7 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) {
PcsAttr::PCSType Type;
if (!PcsAttr::ConvertStrToPCSType(Str, Type))
llvm_unreachable("already validated the attribute");
- return ::new (Ctx) PcsAttr(Attr.getRange(), Ctx, Type,
- Attr.getAttributeSpellingListIndex());
+ return ::new (Ctx) PcsAttr(Ctx, Attr, Type);
}
case ParsedAttr::AT_IntelOclBicc:
return createSimpleAttr<IntelOclBiccAttr>(Ctx, Attr);
@@ -7343,7 +7341,7 @@ static void HandleOpenCLAccessAttr(QualType &CurType, const ParsedAttr &Attr,
} else {
llvm_unreachable("unexpected type");
}
- StringRef AttrName = Attr.getName()->getName();
+ StringRef AttrName = Attr.getAttrName()->getName();
if (PrevAccessQual == AttrName.ltrim("_")) {
// Duplicated qualifiers
S.Diag(Attr.getLoc(), diag::warn_duplicate_declspec)
@@ -7390,8 +7388,22 @@ static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State,
bool IsPointee =
ChunkIndex > 0 &&
(D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Pointer ||
- D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::BlockPointer ||
- D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Reference);
+ D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Reference ||
+ D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::BlockPointer);
+ // For pointers/references to arrays the next chunk is always an array
+ // followed by any number of parentheses.
+ if (!IsPointee && ChunkIndex > 1) {
+ auto AdjustedCI = ChunkIndex - 1;
+ if (D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Array)
+ AdjustedCI--;
+ // Skip over all parentheses.
+ while (AdjustedCI > 0 &&
+ D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Paren)
+ AdjustedCI--;
+ if (D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Pointer ||
+ D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Reference)
+ IsPointee = true;
+ }
bool IsFuncReturnType =
ChunkIndex > 0 &&
D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Function;
@@ -7526,7 +7538,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
IsTypeAttr
? diag::warn_gcc_ignores_type_attr
: diag::warn_cxx11_gnu_attribute_on_type)
- << attr.getName();
+ << attr;
if (!IsTypeAttr)
continue;
}
@@ -7555,7 +7567,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
if (attr.isCXX11Attribute() && TAL == TAL_DeclChunk)
state.getSema().Diag(attr.getLoc(),
diag::warn_unknown_attribute_ignored)
- << attr.getName();
+ << attr;
break;
case ParsedAttr::IgnoredAttribute:
@@ -7720,7 +7732,9 @@ void Sema::completeExprArrayBound(Expr *E) {
auto *Def = Var->getDefinition();
if (!Def) {
SourceLocation PointOfInstantiation = E->getExprLoc();
- InstantiateVariableDefinition(PointOfInstantiation, Var);
+ runWithSufficientStackSpace(PointOfInstantiation, [&] {
+ InstantiateVariableDefinition(PointOfInstantiation, Var);
+ });
Def = Var->getDefinition();
// If we don't already have a point of instantiation, and we managed
@@ -7947,14 +7961,16 @@ static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) {
break;
}
- RD->addAttr(MSInheritanceAttr::CreateImplicit(
- S.getASTContext(), IM,
- /*BestCase=*/S.MSPointerToMemberRepresentationMethod ==
- LangOptions::PPTMK_BestCase,
- S.ImplicitMSInheritanceAttrLoc.isValid()
- ? S.ImplicitMSInheritanceAttrLoc
- : RD->getSourceRange()));
- S.Consumer.AssignInheritanceModel(RD);
+ SourceRange Loc =
+ S.ImplicitMSInheritanceAttrLoc.isValid()
+ ? S.ImplicitMSInheritanceAttrLoc
+ : RD->getSourceRange();
+ RD->addAttr(MSInheritanceAttr::CreateImplicit(
+ S.getASTContext(),
+ /*BestCase=*/S.MSPointerToMemberRepresentationMethod ==
+ LangOptions::PPTMK_BestCase,
+ Loc, AttributeCommonInfo::AS_Microsoft, IM));
+ S.Consumer.AssignInheritanceModel(RD);
}
}
@@ -8058,9 +8074,11 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
} else if (auto *ClassTemplateSpec =
dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) {
- Diagnosed = InstantiateClassTemplateSpecialization(
- Loc, ClassTemplateSpec, TSK_ImplicitInstantiation,
- /*Complain=*/Diagnoser);
+ runWithSufficientStackSpace(Loc, [&] {
+ Diagnosed = InstantiateClassTemplateSpecialization(
+ Loc, ClassTemplateSpec, TSK_ImplicitInstantiation,
+ /*Complain=*/Diagnoser);
+ });
Instantiated = true;
}
} else {
@@ -8071,10 +8089,12 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
// This record was instantiated from a class within a template.
if (MSI->getTemplateSpecializationKind() !=
TSK_ExplicitSpecialization) {
- Diagnosed = InstantiateClass(Loc, RD, Pattern,
- getTemplateInstantiationArgs(RD),
- TSK_ImplicitInstantiation,
- /*Complain=*/Diagnoser);
+ runWithSufficientStackSpace(Loc, [&] {
+ Diagnosed = InstantiateClass(Loc, RD, Pattern,
+ getTemplateInstantiationArgs(RD),
+ TSK_ImplicitInstantiation,
+ /*Complain=*/Diagnoser);
+ });
Instantiated = true;
}
}
@@ -8222,20 +8242,28 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
return true;
}
}
- } else if (!RD->hasTrivialDestructor()) {
- // All fields and bases are of literal types, so have trivial destructors.
- // If this class's destructor is non-trivial it must be user-declared.
+ } else if (getLangOpts().CPlusPlus2a ? !RD->hasConstexprDestructor()
+ : !RD->hasTrivialDestructor()) {
+ // All fields and bases are of literal types, so have trivial or constexpr
+ // destructors. If this class's destructor is non-trivial / non-constexpr,
+ // it must be user-declared.
CXXDestructorDecl *Dtor = RD->getDestructor();
assert(Dtor && "class has literal fields and bases but no dtor?");
if (!Dtor)
return true;
- Diag(Dtor->getLocation(), Dtor->isUserProvided() ?
- diag::note_non_literal_user_provided_dtor :
- diag::note_non_literal_nontrivial_dtor) << RD;
- if (!Dtor->isUserProvided())
- SpecialMemberIsTrivial(Dtor, CXXDestructor, TAH_IgnoreTrivialABI,
- /*Diagnose*/true);
+ if (getLangOpts().CPlusPlus2a) {
+ Diag(Dtor->getLocation(), diag::note_non_literal_non_constexpr_dtor)
+ << RD;
+ } else {
+ Diag(Dtor->getLocation(), Dtor->isUserProvided()
+ ? diag::note_non_literal_user_provided_dtor
+ : diag::note_non_literal_nontrivial_dtor)
+ << RD;
+ if (!Dtor->isUserProvided())
+ SpecialMemberIsTrivial(Dtor, CXXDestructor, TAH_IgnoreTrivialABI,
+ /*Diagnose*/ true);
+ }
}
return true;
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 8df18b5c2784..4b3a6708717c 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -795,6 +795,7 @@ public:
QualType RebuildConstantArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
const llvm::APInt &Size,
+ Expr *SizeExpr,
unsigned IndexTypeQuals,
SourceRange BracketsRange);
@@ -2167,13 +2168,12 @@ public:
ExprResult RebuildDeclRefExpr(NestedNameSpecifierLoc QualifierLoc,
ValueDecl *VD,
const DeclarationNameInfo &NameInfo,
+ NamedDecl *Found,
TemplateArgumentListInfo *TemplateArgs) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
-
- // FIXME: loses template args.
-
- return getSema().BuildDeclarationNameExpr(SS, NameInfo, VD);
+ return getSema().BuildDeclarationNameExpr(SS, NameInfo, VD, Found,
+ TemplateArgs);
}
/// Build a new expression in parentheses.
@@ -2353,6 +2353,17 @@ public:
return getSema().BuildBinOp(/*Scope=*/nullptr, OpLoc, Opc, LHS, RHS);
}
+ /// Build a new rewritten operator expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildCXXRewrittenBinaryOperator(
+ SourceLocation OpLoc, BinaryOperatorKind Opcode,
+ const UnresolvedSetImpl &UnqualLookups, Expr *LHS, Expr *RHS) {
+ return getSema().CreateOverloadedBinOp(OpLoc, Opcode, UnqualLookups, LHS,
+ RHS, /*RequiresADL*/false);
+ }
+
/// Build a new conditional operator expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -2417,7 +2428,7 @@ public:
ExprResult RebuildInitList(SourceLocation LBraceLoc,
MultiExprArg Inits,
SourceLocation RBraceLoc) {
- return SemaRef.ActOnInitList(LBraceLoc, Inits, RBraceLoc);
+ return SemaRef.BuildInitList(LBraceLoc, Inits, RBraceLoc);
}
/// Build a new designated initializer expression.
@@ -3019,6 +3030,25 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildConceptSpecializationExpr(NestedNameSpecifierLoc NNS,
+ SourceLocation TemplateKWLoc, SourceLocation ConceptNameLoc,
+ NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
+ TemplateArgumentListInfo *TALI) {
+ CXXScopeSpec SS;
+ SS.Adopt(NNS);
+ ExprResult Result = getSema().CheckConceptTemplateId(SS, TemplateKWLoc,
+ ConceptNameLoc,
+ FoundDecl,
+ NamedConcept, TALI);
+ if (Result.isInvalid())
+ return ExprError();
+ return Result;
+ }
+
+ /// \brief Build a new Objective-C boxed expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
ExprResult RebuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
return getSema().BuildObjCBoxedExpr(SR, ValueExpr);
}
@@ -3309,16 +3339,14 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildAtomicExpr(SourceLocation BuiltinLoc,
- MultiExprArg SubExprs,
- QualType RetTy,
+ ExprResult RebuildAtomicExpr(SourceLocation BuiltinLoc, MultiExprArg SubExprs,
AtomicExpr::AtomicOp Op,
SourceLocation RParenLoc) {
- // Just create the expression; there is not any interesting semantic
- // analysis here because we can't actually build an AtomicExpr until
- // we are sure it is semantically sound.
- return new (SemaRef.Context) AtomicExpr(BuiltinLoc, SubExprs, RetTy, Op,
- RParenLoc);
+ // Use this for all of the locations, since we don't know the difference
+ // between the call and the expr at this point.
+ SourceRange Range{BuiltinLoc, RParenLoc};
+ return getSema().BuildAtomicExpr(Range, Range, RParenLoc, SubExprs, Op,
+ Sema::AtomicArgumentOrder::AST);
}
private:
@@ -4641,7 +4669,7 @@ TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB,
// Objective-C ARC can add lifetime qualifiers to the type that we're
// referring to.
TLB.TypeWasModifiedSafely(
- Result->getAs<ReferenceType>()->getPointeeTypeAsWritten());
+ Result->castAs<ReferenceType>()->getPointeeTypeAsWritten());
// r-value references can be rebuilt as l-value references.
ReferenceTypeLoc NewTL;
@@ -4729,12 +4757,25 @@ TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB,
if (ElementType.isNull())
return QualType();
+ // Prefer the expression from the TypeLoc; the other may have been uniqued.
+ Expr *OldSize = TL.getSizeExpr();
+ if (!OldSize)
+ OldSize = const_cast<Expr*>(T->getSizeExpr());
+ Expr *NewSize = nullptr;
+ if (OldSize) {
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ NewSize = getDerived().TransformExpr(OldSize).template getAs<Expr>();
+ NewSize = SemaRef.ActOnConstantExpression(NewSize).get();
+ }
+
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
- ElementType != T->getElementType()) {
+ ElementType != T->getElementType() ||
+ (T->getSizeExpr() && NewSize != OldSize)) {
Result = getDerived().RebuildConstantArrayType(ElementType,
T->getSizeModifier(),
- T->getSize(),
+ T->getSize(), NewSize,
T->getIndexTypeCVRQualifiers(),
TL.getBracketsRange());
if (Result.isNull())
@@ -4748,15 +4789,7 @@ TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB,
ArrayTypeLoc NewTL = TLB.push<ArrayTypeLoc>(Result);
NewTL.setLBracketLoc(TL.getLBracketLoc());
NewTL.setRBracketLoc(TL.getRBracketLoc());
-
- Expr *Size = TL.getSizeExpr();
- if (Size) {
- EnterExpressionEvaluationContext Unevaluated(
- SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
- Size = getDerived().TransformExpr(Size).template getAs<Expr>();
- Size = SemaRef.ActOnConstantExpression(Size).get();
- }
- NewTL.setSizeExpr(Size);
+ NewTL.setSizeExpr(NewSize);
return Result;
}
@@ -5928,7 +5961,7 @@ QualType TreeTransform<Derived>::TransformPipeType(TypeLocBuilder &TLB,
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() || ValueType != TL.getValueLoc().getType()) {
- const PipeType *PT = Result->getAs<PipeType>();
+ const PipeType *PT = Result->castAs<PipeType>();
bool isReadPipe = PT->isReadOnly();
Result = getDerived().RebuildPipeType(ValueType, TL.getKWLoc(), isReadPipe);
if (Result.isNull())
@@ -8244,6 +8277,39 @@ StmtResult TreeTransform<Derived>::TransformOMPTaskLoopSimdDirective(
}
template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPMasterTaskLoopDirective(
+ OMPMasterTaskLoopDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_master_taskloop, DirName,
+ nullptr, D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPMasterTaskLoopSimdDirective(
+ OMPMasterTaskLoopSimdDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_master_taskloop_simd, DirName,
+ nullptr, D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPParallelMasterTaskLoopDirective(
+ OMPParallelMasterTaskLoopDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(
+ OMPD_parallel_master_taskloop, DirName, nullptr, D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
StmtResult TreeTransform<Derived>::TransformOMPDistributeDirective(
OMPDistributeDirective *D) {
DeclarationNameInfo DirName;
@@ -9204,6 +9270,14 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
if (!ND)
return ExprError();
+ NamedDecl *Found = ND;
+ if (E->getFoundDecl() != E->getDecl()) {
+ Found = cast_or_null<NamedDecl>(
+ getDerived().TransformDecl(E->getLocation(), E->getFoundDecl()));
+ if (!Found)
+ return ExprError();
+ }
+
DeclarationNameInfo NameInfo = E->getNameInfo();
if (NameInfo.getName()) {
NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo);
@@ -9214,6 +9288,7 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
if (!getDerived().AlwaysRebuild() &&
QualifierLoc == E->getQualifierLoc() &&
ND == E->getDecl() &&
+ Found == E->getFoundDecl() &&
NameInfo.getName() == E->getDecl()->getDeclName() &&
!E->hasExplicitTemplateArgs()) {
@@ -9236,7 +9311,7 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
}
return getDerived().RebuildDeclRefExpr(QualifierLoc, ND, NameInfo,
- TemplateArgs);
+ Found, TemplateArgs);
}
template<typename Derived>
@@ -9705,6 +9780,50 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) {
LHS.get(), RHS.get());
}
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformCXXRewrittenBinaryOperator(
+ CXXRewrittenBinaryOperator *E) {
+ CXXRewrittenBinaryOperator::DecomposedForm Decomp = E->getDecomposedForm();
+
+ ExprResult LHS = getDerived().TransformExpr(const_cast<Expr*>(Decomp.LHS));
+ if (LHS.isInvalid())
+ return ExprError();
+
+ ExprResult RHS = getDerived().TransformExpr(const_cast<Expr*>(Decomp.RHS));
+ if (RHS.isInvalid())
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ LHS.get() == Decomp.LHS &&
+ RHS.get() == Decomp.RHS)
+ return E;
+
+ // Extract the already-resolved callee declarations so that we can restrict
+ // ourselves to using them as the unqualified lookup results when rebuilding.
+ UnresolvedSet<2> UnqualLookups;
+ Expr *PossibleBinOps[] = {E->getSemanticForm(),
+ const_cast<Expr *>(Decomp.InnerBinOp)};
+ for (Expr *PossibleBinOp : PossibleBinOps) {
+ auto *Op = dyn_cast<CXXOperatorCallExpr>(PossibleBinOp->IgnoreImplicit());
+ if (!Op)
+ continue;
+ auto *Callee = dyn_cast<DeclRefExpr>(Op->getCallee()->IgnoreImplicit());
+ if (!Callee || isa<CXXMethodDecl>(Callee->getDecl()))
+ continue;
+
+ // Transform the callee in case we built a call to a local extern
+ // declaration.
+ NamedDecl *Found = cast_or_null<NamedDecl>(getDerived().TransformDecl(
+ E->getOperatorLoc(), Callee->getFoundDecl()));
+ if (!Found)
+ return ExprError();
+ UnqualLookups.addDecl(Found);
+ }
+
+ return getDerived().RebuildCXXRewrittenBinaryOperator(
+ E->getOperatorLoc(), Decomp.Opcode, UnqualLookups, LHS.get(), RHS.get());
+}
+
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCompoundAssignOperator(
@@ -10982,6 +11101,23 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformConceptSpecializationExpr(
+ ConceptSpecializationExpr *E) {
+ const ASTTemplateArgumentListInfo *Old = E->getTemplateArgsAsWritten();
+ TemplateArgumentListInfo TransArgs(Old->LAngleLoc, Old->RAngleLoc);
+ if (getDerived().TransformTemplateArguments(Old->getTemplateArgs(),
+ Old->NumTemplateArgs, TransArgs))
+ return ExprError();
+
+ return getDerived().RebuildConceptSpecializationExpr(
+ E->getNestedNameSpecifierLoc(), E->getTemplateKWLoc(),
+ E->getConceptNameLoc(), E->getFoundDecl(), E->getNamedConcept(),
+ &TransArgs);
+}
+
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
TypeSourceInfo *T = getDerived().TransformType(E->getQueriedTypeSourceInfo());
if (!T)
@@ -11318,10 +11454,14 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
}
}
+ LambdaScopeInfo *LSI = getSema().PushLambdaScope();
+ Sema::FunctionScopeRAII FuncScopeCleanup(getSema());
+
// Transform the template parameters, and add them to the current
// instantiation scope. The null case is handled correctly.
auto TPL = getDerived().TransformTemplateParameterList(
E->getTemplateParameterList());
+ LSI->GLTemplateParameterList = TPL;
// Transform the type of the original lambda's call operator.
// The transformation MUST be done in the CurrentInstantiationScope since
@@ -11348,10 +11488,6 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
NewCallOpType);
}
- LambdaScopeInfo *LSI = getSema().PushLambdaScope();
- Sema::FunctionScopeRAII FuncScopeCleanup(getSema());
- LSI->GLTemplateParameterList = TPL;
-
// Create the local class that will describe the lambda.
CXXRecordDecl *OldClass = E->getLambdaClass();
CXXRecordDecl *Class
@@ -11361,17 +11497,18 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
E->getCaptureDefault());
getDerived().transformedLocalDecl(OldClass, {Class});
- Optional<std::pair<unsigned, Decl*>> Mangling;
+ Optional<std::tuple<unsigned, bool, Decl *>> Mangling;
if (getDerived().ReplacingOriginal())
- Mangling = std::make_pair(OldClass->getLambdaManglingNumber(),
- OldClass->getLambdaContextDecl());
+ Mangling = std::make_tuple(OldClass->getLambdaManglingNumber(),
+ OldClass->hasKnownLambdaInternalLinkage(),
+ OldClass->getLambdaContextDecl());
// Build the call operator.
CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition(
Class, E->getIntroducerRange(), NewCallOpTSI,
E->getCallOperator()->getEndLoc(),
NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
- E->getCallOperator()->getConstexprKind(), Mangling);
+ E->getCallOperator()->getConstexprKind());
LSI->CallOperator = NewCallOperator;
@@ -11391,6 +11528,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator});
+ // Number the lambda for linkage purposes if necessary.
+ getSema().handleLambdaNumbering(Class, NewCallOperator, Mangling);
+
// Introduce the context of the call operator.
Sema::ContextRAII SavedContext(getSema(), NewCallOperator,
/*NewThisContext*/false);
@@ -11663,7 +11803,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
} else {
OldBase = nullptr;
BaseType = getDerived().TransformType(E->getBaseType());
- ObjectType = BaseType->getAs<PointerType>()->getPointeeType();
+ ObjectType = BaseType->castAs<PointerType>()->getPointeeType();
}
// Transform the first part of the nested-name-specifier that qualifies
@@ -12666,7 +12806,6 @@ TreeTransform<Derived>::TransformAsTypeExpr(AsTypeExpr *E) {
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformAtomicExpr(AtomicExpr *E) {
- QualType RetTy = getDerived().TransformType(E->getType());
bool ArgumentChanged = false;
SmallVector<Expr*, 8> SubExprs;
SubExprs.reserve(E->getNumSubExprs());
@@ -12679,7 +12818,7 @@ TreeTransform<Derived>::TransformAtomicExpr(AtomicExpr *E) {
return E;
return getDerived().RebuildAtomicExpr(E->getBuiltinLoc(), SubExprs,
- RetTy, E->getOp(), E->getRParenLoc());
+ E->getOp(), E->getRParenLoc());
}
//===----------------------------------------------------------------------===//
@@ -12797,9 +12936,10 @@ QualType
TreeTransform<Derived>::RebuildConstantArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
const llvm::APInt &Size,
+ Expr *SizeExpr,
unsigned IndexTypeQuals,
SourceRange BracketsRange) {
- return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, nullptr,
+ return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, SizeExpr,
IndexTypeQuals, BracketsRange);
}
@@ -13183,7 +13323,7 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
if (Base->isTypeDependent() || Destroyed.getIdentifier() ||
(!isArrow && !BaseType->getAs<RecordType>()) ||
(isArrow && BaseType->getAs<PointerType>() &&
- !BaseType->getAs<PointerType>()->getPointeeType()
+ !BaseType->castAs<PointerType>()->getPointeeType()
->template getAs<RecordType>())){
// This pseudo-destructor expression is still a pseudo-destructor.
return SemaRef.BuildPseudoDestructorExpr(
diff --git a/lib/Sema/TypeLocBuilder.cpp b/lib/Sema/TypeLocBuilder.cpp
index b451403544ed..2dcbbd83c691 100644
--- a/lib/Sema/TypeLocBuilder.cpp
+++ b/lib/Sema/TypeLocBuilder.cpp
@@ -51,7 +51,7 @@ void TypeLocBuilder::grow(size_t NewCapacity) {
&Buffer[Index],
Capacity - Index);
- if (Buffer != InlineBuffer.buffer)
+ if (Buffer != InlineBuffer)
delete[] Buffer;
Buffer = NewBuffer;
diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h
index 1e6883926a80..738f731c9fe2 100644
--- a/lib/Sema/TypeLocBuilder.h
+++ b/lib/Sema/TypeLocBuilder.h
@@ -39,18 +39,16 @@ class TypeLocBuilder {
/// The inline buffer.
enum { BufferMaxAlignment = alignof(void *) };
- llvm::AlignedCharArray<BufferMaxAlignment, InlineCapacity> InlineBuffer;
+ alignas(BufferMaxAlignment) char InlineBuffer[InlineCapacity];
unsigned NumBytesAtAlign4, NumBytesAtAlign8;
- public:
+public:
TypeLocBuilder()
- : Buffer(InlineBuffer.buffer), Capacity(InlineCapacity),
- Index(InlineCapacity), NumBytesAtAlign4(0), NumBytesAtAlign8(0)
- {
- }
+ : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity),
+ NumBytesAtAlign4(0), NumBytesAtAlign8(0) {}
~TypeLocBuilder() {
- if (Buffer != InlineBuffer.buffer)
+ if (Buffer != InlineBuffer)
delete[] Buffer;
}