aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaType.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaType.cpp693
1 files changed, 444 insertions, 249 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp
index f3747eaa5cb5..ae9a3ee790e1 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp
@@ -106,6 +106,7 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
case AttributeList::AT_FastCall: \
case AttributeList::AT_StdCall: \
case AttributeList::AT_ThisCall: \
+ case AttributeList::AT_RegCall: \
case AttributeList::AT_Pascal: \
case AttributeList::AT_SwiftCall: \
case AttributeList::AT_VectorCall: \
@@ -717,6 +718,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
/*NumExceptions=*/0,
/*NoexceptExpr=*/nullptr,
/*ExceptionSpecTokens=*/nullptr,
+ /*DeclsInPrototype=*/None,
loc, loc, declarator));
// For consistency, make sure the state still has us as processing
@@ -1000,55 +1002,27 @@ static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type,
return S.Context.getObjCObjectType(type, finalTypeArgs, { }, false);
}
-/// Apply Objective-C protocol qualifiers to the given type.
-static QualType applyObjCProtocolQualifiers(
- Sema &S, SourceLocation loc, SourceRange range, QualType type,
- ArrayRef<ObjCProtocolDecl *> protocols,
- const SourceLocation *protocolLocs,
- bool failOnError = false) {
- ASTContext &ctx = S.Context;
- if (const ObjCObjectType *objT = dyn_cast<ObjCObjectType>(type.getTypePtr())){
- // FIXME: Check for protocols to which the class type is already
- // known to conform.
-
- return ctx.getObjCObjectType(objT->getBaseType(),
- objT->getTypeArgsAsWritten(),
- protocols,
- objT->isKindOfTypeAsWritten());
- }
-
- if (type->isObjCObjectType()) {
- // Silently overwrite any existing protocol qualifiers.
- // TODO: determine whether that's the right thing to do.
-
- // FIXME: Check for protocols to which the class type is already
- // known to conform.
- return ctx.getObjCObjectType(type, { }, protocols, false);
- }
-
- // id<protocol-list>
- if (type->isObjCIdType()) {
- const ObjCObjectPointerType *objPtr = type->castAs<ObjCObjectPointerType>();
- type = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, protocols,
- objPtr->isKindOfType());
- return ctx.getObjCObjectPointerType(type);
- }
-
- // Class<protocol-list>
- if (type->isObjCClassType()) {
- const ObjCObjectPointerType *objPtr = type->castAs<ObjCObjectPointerType>();
- type = ctx.getObjCObjectType(ctx.ObjCBuiltinClassTy, { }, protocols,
- objPtr->isKindOfType());
- return ctx.getObjCObjectPointerType(type);
+QualType Sema::BuildObjCTypeParamType(const ObjCTypeParamDecl *Decl,
+ SourceLocation ProtocolLAngleLoc,
+ ArrayRef<ObjCProtocolDecl *> Protocols,
+ ArrayRef<SourceLocation> ProtocolLocs,
+ SourceLocation ProtocolRAngleLoc,
+ bool FailOnError) {
+ QualType Result = QualType(Decl->getTypeForDecl(), 0);
+ if (!Protocols.empty()) {
+ bool HasError;
+ Result = Context.applyObjCProtocolQualifiers(Result, Protocols,
+ HasError);
+ if (HasError) {
+ Diag(SourceLocation(), diag::err_invalid_protocol_qualifiers)
+ << SourceRange(ProtocolLAngleLoc, ProtocolRAngleLoc);
+ if (FailOnError) Result = QualType();
+ }
+ if (FailOnError && Result.isNull())
+ return QualType();
}
- S.Diag(loc, diag::err_invalid_protocol_qualifiers)
- << range;
-
- if (failOnError)
- return QualType();
-
- return type;
+ return Result;
}
QualType Sema::BuildObjCObjectType(QualType BaseType,
@@ -1072,12 +1046,14 @@ QualType Sema::BuildObjCObjectType(QualType BaseType,
}
if (!Protocols.empty()) {
- Result = applyObjCProtocolQualifiers(*this, Loc,
- SourceRange(ProtocolLAngleLoc,
- ProtocolRAngleLoc),
- Result, Protocols,
- ProtocolLocs.data(),
- FailOnError);
+ bool HasError;
+ Result = Context.applyObjCProtocolQualifiers(Result, Protocols,
+ HasError);
+ if (HasError) {
+ Diag(Loc, diag::err_invalid_protocol_qualifiers)
+ << SourceRange(ProtocolLAngleLoc, ProtocolRAngleLoc);
+ if (FailOnError) Result = QualType();
+ }
if (FailOnError && Result.isNull())
return QualType();
}
@@ -1153,7 +1129,7 @@ TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers(
ActualTypeArgInfos.clear();
break;
}
-
+
assert(TypeArgInfo && "No type source info?");
ActualTypeArgInfos.push_back(TypeArgInfo);
}
@@ -1170,7 +1146,7 @@ TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers(
if (Result == T)
return BaseType;
-
+
// Create source information for this type.
TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result);
TypeLoc ResultTL = ResultTInfo->getTypeLoc();
@@ -1183,6 +1159,20 @@ TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers(
ResultTL = ObjCObjectPointerTL.getPointeeLoc();
}
+ if (auto OTPTL = ResultTL.getAs<ObjCTypeParamTypeLoc>()) {
+ // Protocol qualifier information.
+ if (OTPTL.getNumProtocols() > 0) {
+ assert(OTPTL.getNumProtocols() == Protocols.size());
+ OTPTL.setProtocolLAngleLoc(ProtocolLAngleLoc);
+ OTPTL.setProtocolRAngleLoc(ProtocolRAngleLoc);
+ for (unsigned i = 0, n = Protocols.size(); i != n; ++i)
+ OTPTL.setProtocolLoc(i, ProtocolLocs[i]);
+ }
+
+ // We're done. Return the completed type to the parser.
+ return CreateParsedType(Result, ResultTInfo);
+ }
+
auto ObjCObjectTL = ResultTL.castAs<ObjCObjectTypeLoc>();
// Type argument information.
@@ -1220,19 +1210,19 @@ TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers(
return CreateParsedType(Result, ResultTInfo);
}
-static StringRef getImageAccessAttrStr(AttributeList *attrs) {
- if (attrs) {
-
- AttributeList *Next;
+static OpenCLAccessAttr::Spelling getImageAccess(const AttributeList *Attrs) {
+ if (Attrs) {
+ const AttributeList *Next = Attrs;
do {
- AttributeList &Attr = *attrs;
+ const AttributeList &Attr = *Next;
Next = Attr.getNext();
if (Attr.getKind() == AttributeList::AT_OpenCLAccess) {
- return Attr.getName()->getName();
+ return static_cast<OpenCLAccessAttr::Spelling>(
+ Attr.getSemanticSpelling());
}
} while (Next);
}
- return "";
+ return OpenCLAccessAttr::Keyword_read_only;
}
/// \brief Convert the specified declspec to the appropriate type
@@ -1411,14 +1401,6 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
Result = Context.LongDoubleTy;
else
Result = Context.DoubleTy;
-
- if (S.getLangOpts().OpenCL &&
- !((S.getLangOpts().OpenCLVersion >= 120) ||
- S.getOpenCLOptions().cl_khr_fp64)) {
- S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_requires_extension)
- << Result << "cl_khr_fp64";
- declarator.setInvalidType(true);
- }
break;
case DeclSpec::TST_float128:
if (!S.Context.getTargetInfo().hasFloat128Type())
@@ -1470,48 +1452,6 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
Result = S.GetTypeFromParser(DS.getRepAsType());
if (Result.isNull()) {
declarator.setInvalidType(true);
- } else if (S.getLangOpts().OpenCL) {
- if (Result->getAs<AtomicType>()) {
- StringRef TypeName = Result.getBaseTypeIdentifier()->getName();
- bool NoExtTypes =
- llvm::StringSwitch<bool>(TypeName)
- .Cases("atomic_int", "atomic_uint", "atomic_float",
- "atomic_flag", true)
- .Default(false);
- if (!S.getOpenCLOptions().cl_khr_int64_base_atomics && !NoExtTypes) {
- S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_requires_extension)
- << Result << "cl_khr_int64_base_atomics";
- declarator.setInvalidType(true);
- }
- if (!S.getOpenCLOptions().cl_khr_int64_extended_atomics &&
- !NoExtTypes) {
- S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_requires_extension)
- << Result << "cl_khr_int64_extended_atomics";
- declarator.setInvalidType(true);
- }
- if (!S.getOpenCLOptions().cl_khr_fp64 &&
- !TypeName.compare("atomic_double")) {
- S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_requires_extension)
- << Result << "cl_khr_fp64";
- declarator.setInvalidType(true);
- }
- } else if (!S.getOpenCLOptions().cl_khr_gl_msaa_sharing &&
- (Result->isOCLImage2dArrayMSAADepthROType() ||
- Result->isOCLImage2dArrayMSAADepthWOType() ||
- Result->isOCLImage2dArrayMSAADepthRWType() ||
- Result->isOCLImage2dArrayMSAAROType() ||
- Result->isOCLImage2dArrayMSAARWType() ||
- Result->isOCLImage2dArrayMSAAWOType() ||
- Result->isOCLImage2dMSAADepthROType() ||
- Result->isOCLImage2dMSAADepthRWType() ||
- Result->isOCLImage2dMSAADepthWOType() ||
- Result->isOCLImage2dMSAAROType() ||
- Result->isOCLImage2dMSAARWType() ||
- Result->isOCLImage2dMSAAWOType())) {
- S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_requires_extension)
- << Result << "cl_khr_gl_msaa_sharing";
- declarator.setInvalidType(true);
- }
}
// TypeQuals handled by caller.
@@ -1623,11 +1563,14 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
#define GENERIC_IMAGE_TYPE(ImgType, Id) \
case DeclSpec::TST_##ImgType##_t: \
- Result = llvm::StringSwitch<QualType>( \
- getImageAccessAttrStr(DS.getAttributes().getList())) \
- .Cases("write_only", "__write_only", Context.Id##WOTy) \
- .Cases("read_write", "__read_write", Context.Id##RWTy) \
- .Default(Context.Id##ROTy); \
+ switch (getImageAccess(DS.getAttributes().getList())) { \
+ case OpenCLAccessAttr::Keyword_write_only: \
+ Result = Context.Id##WOTy; break; \
+ case OpenCLAccessAttr::Keyword_read_write: \
+ Result = Context.Id##RWTy; break; \
+ case OpenCLAccessAttr::Keyword_read_only: \
+ Result = Context.Id##ROTy; break; \
+ } \
break;
#include "clang/Basic/OpenCLImageTypes.def"
@@ -1637,6 +1580,10 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
break;
}
+ if (S.getLangOpts().OpenCL &&
+ S.checkOpenCLDisabledTypeDeclSpec(DS, Result))
+ declarator.setInvalidType(true);
+
// Handle complex types.
if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) {
if (S.getLangOpts().Freestanding)
@@ -1748,6 +1695,12 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
if (T.isNull())
return QualType();
+ // Ignore any attempt to form a cv-qualified reference.
+ if (T->isReferenceType()) {
+ Qs.removeConst();
+ Qs.removeVolatile();
+ }
+
// Enforce C99 6.7.3p2: "Types other than pointer types derived from
// object or incomplete types shall not be restrict-qualified."
if (Qs.hasRestrict()) {
@@ -1789,6 +1742,11 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
if (T.isNull())
return QualType();
+ // Ignore any attempt to form a cv-qualified reference.
+ if (T->isReferenceType())
+ CVRAU &=
+ ~(DeclSpec::TQ_const | DeclSpec::TQ_volatile | DeclSpec::TQ_atomic);
+
// Convert from DeclSpec::TQ to Qualifiers::TQ by just dropping TQ_atomic and
// TQ_unaligned;
unsigned CVR = CVRAU & ~(DeclSpec::TQ_atomic | DeclSpec::TQ_unaligned);
@@ -2030,7 +1988,7 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
return Context.getRValueReferenceType(T);
}
-/// \brief Build a Pipe type.
+/// \brief Build a Read-only Pipe type.
///
/// \param T The type to which we'll be building a Pipe.
///
@@ -2038,11 +1996,20 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
///
/// \returns A suitable pipe type, if there are no errors. Otherwise, returns a
/// NULL type.
-QualType Sema::BuildPipeType(QualType T, SourceLocation Loc) {
- assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType");
+QualType Sema::BuildReadPipeType(QualType T, SourceLocation Loc) {
+ return Context.getReadPipeType(T);
+}
- // Build the pipe type.
- return Context.getPipeType(T);
+/// \brief Build a Write-only Pipe type.
+///
+/// \param T The type to which we'll be building a Pipe.
+///
+/// \param Loc We do not use it for now.
+///
+/// \returns A suitable pipe type, if there are no errors. Otherwise, returns a
+/// NULL type.
+QualType Sema::BuildWritePipeType(QualType T, SourceLocation Loc) {
+ return Context.getWritePipeType(T);
}
/// Check whether the specified array size makes the array type a VLA. If so,
@@ -2242,6 +2209,10 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
Diag(Loc, diag::err_opencl_vla);
return QualType();
}
+ // CUDA device code doesn't support VLAs.
+ if (getLangOpts().CUDA && T->isVariableArrayType())
+ CUDADiagIfDeviceCode(Loc, diag::err_cuda_vla) << CurrentCUDATarget();
+
// If this is not C99, extwarn about VLA's and C99 array size modifiers.
if (!getLangOpts().C99) {
if (T->isVariableArrayType()) {
@@ -2390,28 +2361,16 @@ static void checkExtParameterInfos(Sema &S, ArrayRef<QualType> paramTypes,
}
continue;
- // swift_context parameters must be the last parameter except for
- // a possible swift_error parameter.
case ParameterABI::SwiftContext:
checkForSwiftCC(paramIndex);
- if (!(paramIndex == numParams - 1 ||
- (paramIndex == numParams - 2 &&
- EPI.ExtParameterInfos[numParams - 1].getABI()
- == ParameterABI::SwiftErrorResult))) {
- S.Diag(getParamLoc(paramIndex),
- diag::err_swift_context_not_before_swift_error_result);
- }
continue;
- // swift_error parameters must be the last parameter.
+ // swift_error parameters must be preceded by a swift_context parameter.
case ParameterABI::SwiftErrorResult:
checkForSwiftCC(paramIndex);
- if (paramIndex != numParams - 1) {
- S.Diag(getParamLoc(paramIndex),
- diag::err_swift_error_result_not_last);
- } else if (paramIndex == 0 ||
- EPI.ExtParameterInfos[paramIndex - 1].getABI()
- != ParameterABI::SwiftContext) {
+ if (paramIndex == 0 ||
+ EPI.ExtParameterInfos[paramIndex - 1].getABI() !=
+ ParameterABI::SwiftContext) {
S.Diag(getParamLoc(paramIndex),
diag::err_swift_error_result_not_after_swift_context);
}
@@ -2855,7 +2814,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
Error = 7; // Exception declaration
break;
case Declarator::TemplateParamContext:
- Error = 8; // Template parameter
+ if (!SemaRef.getLangOpts().CPlusPlus1z)
+ Error = 8; // Template parameter
break;
case Declarator::BlockLiteralContext:
Error = 9; // Block literal
@@ -3212,6 +3172,7 @@ namespace {
Pointer,
BlockPointer,
MemberPointer,
+ Array,
};
} // end anonymous namespace
@@ -3273,15 +3234,27 @@ namespace {
// NSError**
NSErrorPointerPointer,
};
+
+ /// Describes a declarator chunk wrapping a pointer that marks inference as
+ /// unexpected.
+ // These values must be kept in sync with diagnostics.
+ enum class PointerWrappingDeclaratorKind {
+ /// Pointer is top-level.
+ None = -1,
+ /// Pointer is an array element.
+ Array = 0,
+ /// Pointer is the referent type of a C++ reference.
+ Reference = 1
+ };
} // end anonymous namespace
/// Classify the given declarator, whose type-specified is \c type, based on
/// what kind of pointer it refers to.
///
/// This is used to determine the default nullability.
-static PointerDeclaratorKind classifyPointerDeclarator(Sema &S,
- QualType type,
- Declarator &declarator) {
+static PointerDeclaratorKind
+classifyPointerDeclarator(Sema &S, QualType type, Declarator &declarator,
+ PointerWrappingDeclaratorKind &wrappingKind) {
unsigned numNormalPointers = 0;
// For any dependent type, we consider it a non-pointer.
@@ -3293,6 +3266,10 @@ static PointerDeclaratorKind classifyPointerDeclarator(Sema &S,
DeclaratorChunk &chunk = declarator.getTypeObject(i);
switch (chunk.Kind) {
case DeclaratorChunk::Array:
+ if (numNormalPointers == 0)
+ wrappingKind = PointerWrappingDeclaratorKind::Array;
+ break;
+
case DeclaratorChunk::Function:
case DeclaratorChunk::Pipe:
break;
@@ -3303,14 +3280,18 @@ static PointerDeclaratorKind classifyPointerDeclarator(Sema &S,
: PointerDeclaratorKind::SingleLevelPointer;
case DeclaratorChunk::Paren:
+ break;
+
case DeclaratorChunk::Reference:
- continue;
+ if (numNormalPointers == 0)
+ wrappingKind = PointerWrappingDeclaratorKind::Reference;
+ break;
case DeclaratorChunk::Pointer:
++numNormalPointers;
if (numNormalPointers > 2)
return PointerDeclaratorKind::MultiLevelPointer;
- continue;
+ break;
}
}
@@ -3453,12 +3434,77 @@ static FileID getNullabilityCompletenessCheckFileID(Sema &S,
return file;
}
-/// Check for consistent use of nullability.
-static void checkNullabilityConsistency(TypeProcessingState &state,
+/// Creates a fix-it to insert a C-style nullability keyword at \p pointerLoc,
+/// taking into account whitespace before and after.
+static void fixItNullability(Sema &S, DiagnosticBuilder &Diag,
+ SourceLocation PointerLoc,
+ NullabilityKind Nullability) {
+ assert(PointerLoc.isValid());
+ if (PointerLoc.isMacroID())
+ return;
+
+ SourceLocation FixItLoc = S.getLocForEndOfToken(PointerLoc);
+ if (!FixItLoc.isValid() || FixItLoc == PointerLoc)
+ return;
+
+ const char *NextChar = S.SourceMgr.getCharacterData(FixItLoc);
+ if (!NextChar)
+ return;
+
+ SmallString<32> InsertionTextBuf{" "};
+ InsertionTextBuf += getNullabilitySpelling(Nullability);
+ InsertionTextBuf += " ";
+ StringRef InsertionText = InsertionTextBuf.str();
+
+ if (isWhitespace(*NextChar)) {
+ InsertionText = InsertionText.drop_back();
+ } else if (NextChar[-1] == '[') {
+ if (NextChar[0] == ']')
+ InsertionText = InsertionText.drop_back().drop_front();
+ else
+ InsertionText = InsertionText.drop_front();
+ } else if (!isIdentifierBody(NextChar[0], /*allow dollar*/true) &&
+ !isIdentifierBody(NextChar[-1], /*allow dollar*/true)) {
+ InsertionText = InsertionText.drop_back().drop_front();
+ }
+
+ Diag << FixItHint::CreateInsertion(FixItLoc, InsertionText);
+}
+
+static void emitNullabilityConsistencyWarning(Sema &S,
+ SimplePointerKind PointerKind,
+ SourceLocation PointerLoc) {
+ assert(PointerLoc.isValid());
+
+ if (PointerKind == SimplePointerKind::Array) {
+ S.Diag(PointerLoc, diag::warn_nullability_missing_array);
+ } else {
+ S.Diag(PointerLoc, diag::warn_nullability_missing)
+ << static_cast<unsigned>(PointerKind);
+ }
+
+ if (PointerLoc.isMacroID())
+ return;
+
+ auto addFixIt = [&](NullabilityKind Nullability) {
+ auto Diag = S.Diag(PointerLoc, diag::note_nullability_fix_it);
+ Diag << static_cast<unsigned>(Nullability);
+ Diag << static_cast<unsigned>(PointerKind);
+ fixItNullability(S, Diag, PointerLoc, Nullability);
+ };
+ addFixIt(NullabilityKind::Nullable);
+ addFixIt(NullabilityKind::NonNull);
+}
+
+/// Complains about missing nullability if the file containing \p pointerLoc
+/// has other uses of nullability (either the keywords or the \c assume_nonnull
+/// pragma).
+///
+/// If the file has \e not seen other uses of nullability, this particular
+/// pointer is saved for possible later diagnosis. See recordNullabilitySeen().
+static void checkNullabilityConsistency(Sema &S,
SimplePointerKind pointerKind,
SourceLocation pointerLoc) {
- Sema &S = state.getSema();
-
// Determine which file we're performing consistency checking for.
FileID file = getNullabilityCompletenessCheckFileID(S, pointerLoc);
if (file.isInvalid())
@@ -3468,10 +3514,16 @@ static void checkNullabilityConsistency(TypeProcessingState &state,
// about anything.
FileNullability &fileNullability = S.NullabilityMap[file];
if (!fileNullability.SawTypeNullability) {
- // If this is the first pointer declarator in the file, record it.
+ // If this is the first pointer declarator in the file, and the appropriate
+ // warning is on, record it in case we need to diagnose it retroactively.
+ diag::kind diagKind;
+ if (pointerKind == SimplePointerKind::Array)
+ diagKind = diag::warn_nullability_missing_array;
+ else
+ diagKind = diag::warn_nullability_missing;
+
if (fileNullability.PointerLoc.isInvalid() &&
- !S.Context.getDiagnostics().isIgnored(diag::warn_nullability_missing,
- pointerLoc)) {
+ !S.Context.getDiagnostics().isIgnored(diagKind, pointerLoc)) {
fileNullability.PointerLoc = pointerLoc;
fileNullability.PointerKind = static_cast<unsigned>(pointerKind);
}
@@ -3480,8 +3532,66 @@ static void checkNullabilityConsistency(TypeProcessingState &state,
}
// Complain about missing nullability.
- S.Diag(pointerLoc, diag::warn_nullability_missing)
- << static_cast<unsigned>(pointerKind);
+ emitNullabilityConsistencyWarning(S, pointerKind, pointerLoc);
+}
+
+/// Marks that a nullability feature has been used in the file containing
+/// \p loc.
+///
+/// If this file already had pointer types in it that were missing nullability,
+/// the first such instance is retroactively diagnosed.
+///
+/// \sa checkNullabilityConsistency
+static void recordNullabilitySeen(Sema &S, SourceLocation loc) {
+ FileID file = getNullabilityCompletenessCheckFileID(S, loc);
+ if (file.isInvalid())
+ return;
+
+ FileNullability &fileNullability = S.NullabilityMap[file];
+ if (fileNullability.SawTypeNullability)
+ return;
+ fileNullability.SawTypeNullability = true;
+
+ // If we haven't seen any type nullability before, now we have. Retroactively
+ // diagnose the first unannotated pointer, if there was one.
+ if (fileNullability.PointerLoc.isInvalid())
+ return;
+
+ auto kind = static_cast<SimplePointerKind>(fileNullability.PointerKind);
+ emitNullabilityConsistencyWarning(S, kind, fileNullability.PointerLoc);
+}
+
+/// Returns true if any of the declarator chunks before \p endIndex include a
+/// level of indirection: array, pointer, reference, or pointer-to-member.
+///
+/// Because declarator chunks are stored in outer-to-inner order, testing
+/// every chunk before \p endIndex is testing all chunks that embed the current
+/// chunk as part of their type.
+///
+/// It is legal to pass the result of Declarator::getNumTypeObjects() as the
+/// end index, in which case all chunks are tested.
+static bool hasOuterPointerLikeChunk(const Declarator &D, unsigned endIndex) {
+ unsigned i = endIndex;
+ while (i != 0) {
+ // Walk outwards along the declarator chunks.
+ --i;
+ const DeclaratorChunk &DC = D.getTypeObject(i);
+ switch (DC.Kind) {
+ case DeclaratorChunk::Paren:
+ break;
+ case DeclaratorChunk::Array:
+ case DeclaratorChunk::Pointer:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::MemberPointer:
+ return true;
+ case DeclaratorChunk::Function:
+ case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::Pipe:
+ // These are invalid anyway, so just ignore.
+ break;
+ }
+ }
+ return false;
}
static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
@@ -3561,24 +3671,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Are we in an assume-nonnull region?
bool inAssumeNonNullRegion = false;
- if (S.PP.getPragmaAssumeNonNullLoc().isValid()) {
+ SourceLocation assumeNonNullLoc = S.PP.getPragmaAssumeNonNullLoc();
+ if (assumeNonNullLoc.isValid()) {
inAssumeNonNullRegion = true;
- // Determine which file we saw the assume-nonnull region in.
- FileID file = getNullabilityCompletenessCheckFileID(
- S, S.PP.getPragmaAssumeNonNullLoc());
- if (file.isValid()) {
- FileNullability &fileNullability = S.NullabilityMap[file];
-
- // If we haven't seen any type nullability before, now we have.
- if (!fileNullability.SawTypeNullability) {
- if (fileNullability.PointerLoc.isValid()) {
- S.Diag(fileNullability.PointerLoc, diag::warn_nullability_missing)
- << static_cast<unsigned>(fileNullability.PointerKind);
- }
-
- fileNullability.SawTypeNullability = true;
- }
- }
+ recordNullabilitySeen(S, assumeNonNullLoc);
}
// Whether to complain about missing nullability specifiers or not.
@@ -3593,6 +3689,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
CAMN_Yes
} complainAboutMissingNullability = CAMN_No;
unsigned NumPointersRemaining = 0;
+ auto complainAboutInferringWithinChunk = PointerWrappingDeclaratorKind::None;
if (IsTypedefName) {
// For typedefs, we do not infer any nullability (the default),
@@ -3600,7 +3697,17 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// inner pointers.
complainAboutMissingNullability = CAMN_InnerPointers;
- if (T->canHaveNullability() && !T->getNullability(S.Context)) {
+ auto isDependentNonPointerType = [](QualType T) -> bool {
+ // Note: This is intended to be the same check as Type::canHaveNullability
+ // except with all of the ambiguous cases being treated as 'false' rather
+ // than 'true'.
+ return T->isDependentType() && !T->isAnyPointerType() &&
+ !T->isBlockPointerType() && !T->isMemberPointerType();
+ };
+
+ if (T->canHaveNullability() && !T->getNullability(S.Context) &&
+ !isDependentNonPointerType(T)) {
+ // Note that we allow but don't require nullability on dependent types.
++NumPointersRemaining;
}
@@ -3651,11 +3758,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// fallthrough
case Declarator::FileContext:
- case Declarator::KNRTypeListContext:
+ case Declarator::KNRTypeListContext: {
complainAboutMissingNullability = CAMN_Yes;
// Nullability inference depends on the type and declarator.
- switch (classifyPointerDeclarator(S, T, D)) {
+ auto wrappingKind = PointerWrappingDeclaratorKind::None;
+ switch (classifyPointerDeclarator(S, T, D, wrappingKind)) {
case PointerDeclaratorKind::NonPointer:
case PointerDeclaratorKind::MultiLevelPointer:
// Cannot infer nullability.
@@ -3664,6 +3772,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case PointerDeclaratorKind::SingleLevelPointer:
// Infer _Nonnull if we are in an assumes-nonnull region.
if (inAssumeNonNullRegion) {
+ complainAboutInferringWithinChunk = wrappingKind;
inferNullability = NullabilityKind::NonNull;
inferNullabilityCS = (context == Declarator::ObjCParameterContext ||
context == Declarator::ObjCResultContext);
@@ -3704,6 +3813,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
break;
}
break;
+ }
case Declarator::ConversionIdContext:
complainAboutMissingNullability = CAMN_Yes;
@@ -3729,6 +3839,23 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
}
+ // Local function that returns true if its argument looks like a va_list.
+ auto isVaList = [&S](QualType T) -> bool {
+ auto *typedefTy = T->getAs<TypedefType>();
+ if (!typedefTy)
+ return false;
+ TypedefDecl *vaListTypedef = S.Context.getBuiltinVaListDecl();
+ do {
+ if (typedefTy->getDecl() == vaListTypedef)
+ return true;
+ if (auto *name = typedefTy->getDecl()->getIdentifier())
+ if (name->isStr("va_list"))
+ return true;
+ typedefTy = typedefTy->desugar()->getAs<TypedefType>();
+ } while (typedefTy);
+ return false;
+ };
+
// Local function that checks the nullability for a given pointer declarator.
// Returns true if _Nonnull was inferred.
auto inferPointerNullability = [&](SimplePointerKind pointerKind,
@@ -3762,6 +3889,15 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
->setObjCDeclQualifier(ObjCDeclSpec::DQ_CSNullability);
}
+ if (pointerLoc.isValid() &&
+ complainAboutInferringWithinChunk !=
+ PointerWrappingDeclaratorKind::None) {
+ auto Diag =
+ S.Diag(pointerLoc, diag::warn_nullability_inferred_on_nested_type);
+ Diag << static_cast<int>(complainAboutInferringWithinChunk);
+ fixItNullability(S, Diag, pointerLoc, NullabilityKind::NonNull);
+ }
+
if (inferNullabilityInnerOnly)
inferNullabilityInnerOnlyComplete = true;
return nullabilityAttr;
@@ -3779,27 +3915,42 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Fallthrough.
case CAMN_Yes:
- checkNullabilityConsistency(state, pointerKind, pointerLoc);
+ checkNullabilityConsistency(S, pointerKind, pointerLoc);
}
return nullptr;
};
// If the type itself could have nullability but does not, infer pointer
// nullability and perform consistency checking.
- if (T->canHaveNullability() && S.ActiveTemplateInstantiations.empty() &&
- !T->getNullability(S.Context)) {
- SimplePointerKind pointerKind = SimplePointerKind::Pointer;
- if (T->isBlockPointerType())
- pointerKind = SimplePointerKind::BlockPointer;
- else if (T->isMemberPointerType())
- pointerKind = SimplePointerKind::MemberPointer;
+ if (S.ActiveTemplateInstantiations.empty()) {
+ if (T->canHaveNullability() && !T->getNullability(S.Context)) {
+ if (isVaList(T)) {
+ // Record that we've seen a pointer, but do nothing else.
+ if (NumPointersRemaining > 0)
+ --NumPointersRemaining;
+ } else {
+ SimplePointerKind pointerKind = SimplePointerKind::Pointer;
+ if (T->isBlockPointerType())
+ pointerKind = SimplePointerKind::BlockPointer;
+ else if (T->isMemberPointerType())
+ pointerKind = SimplePointerKind::MemberPointer;
+
+ if (auto *attr = inferPointerNullability(
+ pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(),
+ D.getMutableDeclSpec().getAttributes().getListRef())) {
+ T = Context.getAttributedType(
+ AttributedType::getNullabilityAttrKind(*inferNullability),T,T);
+ attr->setUsedAsTypeAttr();
+ }
+ }
+ }
- if (auto *attr = inferPointerNullability(
- pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(),
- D.getMutableDeclSpec().getAttributes().getListRef())) {
- T = Context.getAttributedType(
- AttributedType::getNullabilityAttrKind(*inferNullability), T, T);
- attr->setUsedAsTypeAttr();
+ if (complainAboutMissingNullability == CAMN_Yes &&
+ T->isArrayType() && !T->getNullability(S.Context) && !isVaList(T) &&
+ D.isPrototypeContext() &&
+ !hasOuterPointerLikeChunk(D, D.getNumTypeObjects())) {
+ checkNullabilityConsistency(S, SimplePointerKind::Array,
+ D.getDeclSpec().getTypeSpecTypeLoc());
}
}
@@ -3925,31 +4076,13 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// C99 6.7.5.2p1: ... and then only in the outermost array type
// derivation.
- unsigned x = chunkIndex;
- while (x != 0) {
- // Walk outwards along the declarator chunks.
- x--;
- const DeclaratorChunk &DC = D.getTypeObject(x);
- switch (DC.Kind) {
- case DeclaratorChunk::Paren:
- continue;
- case DeclaratorChunk::Array:
- case DeclaratorChunk::Pointer:
- case DeclaratorChunk::Reference:
- case DeclaratorChunk::MemberPointer:
- S.Diag(DeclType.Loc, diag::err_array_static_not_outermost) <<
- (ASM == ArrayType::Static ? "'static'" : "type qualifier");
- if (ASM == ArrayType::Static)
- ASM = ArrayType::Normal;
- ATI.TypeQuals = 0;
- D.setInvalidType(true);
- break;
- case DeclaratorChunk::Function:
- case DeclaratorChunk::BlockPointer:
- case DeclaratorChunk::Pipe:
- // These are invalid anyway, so just ignore.
- break;
- }
+ if (hasOuterPointerLikeChunk(D, chunkIndex)) {
+ S.Diag(DeclType.Loc, diag::err_array_static_not_outermost) <<
+ (ASM == ArrayType::Static ? "'static'" : "type qualifier");
+ if (ASM == ArrayType::Static)
+ ASM = ArrayType::Normal;
+ ATI.TypeQuals = 0;
+ D.setInvalidType(true);
}
}
const AutoType *AT = T->getContainedAutoType();
@@ -3964,6 +4097,16 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
break;
}
+ // Array parameters can be marked nullable as well, although it's not
+ // necessary if they're marked 'static'.
+ if (complainAboutMissingNullability == CAMN_Yes &&
+ !hasNullabilityAttr(DeclType.getAttrs()) &&
+ ASM != ArrayType::Static &&
+ D.isPrototypeContext() &&
+ !hasOuterPointerLikeChunk(D, chunkIndex)) {
+ checkNullabilityConsistency(S, SimplePointerKind::Array, DeclType.Loc);
+ }
+
T = S.BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals,
SourceRange(DeclType.Loc, DeclType.EndLoc), Name);
break;
@@ -4032,7 +4175,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// FIXME: This really should be in BuildFunctionType.
if (T->isHalfType()) {
if (S.getLangOpts().OpenCL) {
- if (!S.getOpenCLOptions().cl_khr_fp16) {
+ if (!S.getOpenCLOptions().isEnabled("cl_khr_fp16")) {
S.Diag(D.getIdentifierLoc(), diag::err_opencl_invalid_return)
<< T << 0 /*pointer hint*/;
D.setInvalidType(true);
@@ -4044,13 +4187,26 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
}
+ if (LangOpts.OpenCL) {
// OpenCL v2.0 s6.12.5 - A block cannot be the return value of a
// function.
- if (LangOpts.OpenCL && (T->isBlockPointerType() || T->isImageType() ||
- T->isSamplerT() || T->isPipeType())) {
- S.Diag(D.getIdentifierLoc(), diag::err_opencl_invalid_return)
- << T << 1 /*hint off*/;
- D.setInvalidType(true);
+ if (T->isBlockPointerType() || T->isImageType() || T->isSamplerT() ||
+ T->isPipeType()) {
+ S.Diag(D.getIdentifierLoc(), diag::err_opencl_invalid_return)
+ << T << 1 /*hint off*/;
+ D.setInvalidType(true);
+ }
+ // OpenCL doesn't support variadic functions and blocks
+ // (s6.9.e and s6.12.5 OpenCL v2.0) except for printf.
+ // We also allow here any toolchain reserved identifiers.
+ if (FTI.isVariadic &&
+ !(D.getIdentifier() &&
+ ((D.getIdentifier()->getName() == "printf" &&
+ LangOpts.OpenCLVersion >= 120) ||
+ D.getIdentifier()->getName().startswith("__")))) {
+ S.Diag(D.getIdentifierLoc(), diag::err_opencl_variadic_function);
+ D.setInvalidType(true);
+ }
}
// Methods cannot return interface types. All ObjC objects are
@@ -4143,7 +4299,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Exception specs are not allowed in typedefs. Complain, but add it
// anyway.
- if (IsTypedefName && FTI.getExceptionSpecType())
+ if (IsTypedefName && FTI.getExceptionSpecType() && !LangOpts.CPlusPlus1z)
S.Diag(FTI.getExceptionSpecLocBeg(),
diag::err_exception_spec_in_typedef)
<< (D.getContext() == Declarator::AliasDeclContext ||
@@ -4154,6 +4310,19 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (FTI.isAmbiguous)
warnAboutAmbiguousFunction(S, D, DeclType, T);
+ // GNU warning -Wstrict-prototypes
+ // Warn if a function declaration is without a prototype.
+ // This warning is issued for all kinds of unprototyped function
+ // declarations (i.e. function type typedef, function pointer etc.)
+ // C99 6.7.5.3p14:
+ // The empty list in a function declarator that is not part of a
+ // definition of that function specifies that no information
+ // about the number or types of the parameters is supplied.
+ if (D.getFunctionDefinitionKind() == FDK_Declaration &&
+ FTI.NumParams == 0 && !LangOpts.CPlusPlus)
+ S.Diag(DeclType.Loc, diag::warn_strict_prototypes)
+ << 0 << FixItHint::CreateInsertion(FTI.getRParenLoc(), "void");
+
FunctionType::ExtInfo EI(getCCForDeclaratorChunk(S, D, FTI, chunkIndex));
if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.CPlusPlus) {
@@ -4239,7 +4408,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Disallow half FP parameters.
// FIXME: This really should be in BuildFunctionType.
if (S.getLangOpts().OpenCL) {
- if (!S.getOpenCLOptions().cl_khr_fp16) {
+ if (!S.getOpenCLOptions().isEnabled("cl_khr_fp16")) {
S.Diag(Param->getLocation(),
diag::err_opencl_half_param) << ParamTy;
D.setInvalidType();
@@ -4290,7 +4459,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (FTI.getExceptionSpecType() == EST_Dynamic) {
// FIXME: It's rather inefficient to have to split into two vectors
// here.
- unsigned N = FTI.NumExceptions;
+ unsigned N = FTI.getNumExceptions();
DynamicExceptions.reserve(N);
DynamicExceptionRanges.reserve(N);
for (unsigned I = 0; I != N; ++I) {
@@ -4374,7 +4543,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
case DeclaratorChunk::Pipe: {
- T = S.BuildPipeType(T, DeclType.Loc );
+ T = S.BuildReadPipeType(T, DeclType.Loc);
+ processTypeAttrs(state, T, TAL_DeclSpec,
+ D.getDeclSpec().getAttributes().getList());
break;
}
}
@@ -4738,6 +4909,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
return AttributeList::AT_StdCall;
case AttributedType::attr_thiscall:
return AttributeList::AT_ThisCall;
+ case AttributedType::attr_regcall:
+ return AttributeList::AT_RegCall;
case AttributedType::attr_pascal:
return AttributeList::AT_Pascal;
case AttributedType::attr_swiftcall:
@@ -4908,11 +5081,9 @@ namespace {
TL.getWrittenBuiltinSpecs() = DS.getWrittenBuiltinSpecs();
// Try to have a meaningful source location.
if (TL.getWrittenSignSpec() != TSS_unspecified)
- // Sign spec loc overrides the others (e.g., 'unsigned long').
- TL.setBuiltinLoc(DS.getTypeSpecSignLoc());
- else if (TL.getWrittenWidthSpec() != TSW_unspecified)
- // Width spec loc overrides type spec loc (e.g., 'short int').
- TL.setBuiltinLoc(DS.getTypeSpecWidthLoc());
+ TL.expandBuiltinRange(DS.getTypeSpecSignLoc());
+ if (TL.getWrittenWidthSpec() != TSW_unspecified)
+ TL.expandBuiltinRange(DS.getTypeSpecWidthRange());
}
}
void VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
@@ -5537,7 +5708,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
if (Class->isArcWeakrefUnavailable()) {
S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class);
S.Diag(ObjT->getInterfaceDecl()->getLocation(),
- diag::note_class_declared);
+ diag::note_class_declared);
}
}
}
@@ -5811,23 +5982,9 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
bool Sema::checkNullabilityTypeSpecifier(QualType &type,
NullabilityKind nullability,
SourceLocation nullabilityLoc,
- bool isContextSensitive) {
- // We saw a nullability type specifier. If this is the first one for
- // this file, note that.
- FileID file = getNullabilityCompletenessCheckFileID(*this, nullabilityLoc);
- if (!file.isInvalid()) {
- FileNullability &fileNullability = NullabilityMap[file];
- if (!fileNullability.SawTypeNullability) {
- // If we have already seen a pointer declarator without a nullability
- // annotation, complain about it.
- if (fileNullability.PointerLoc.isValid()) {
- Diag(fileNullability.PointerLoc, diag::warn_nullability_missing)
- << static_cast<unsigned>(fileNullability.PointerKind);
- }
-
- fileNullability.SawTypeNullability = true;
- }
- }
+ bool isContextSensitive,
+ bool allowOnArrayType) {
+ recordNullabilitySeen(*this, nullabilityLoc);
// Check for existing nullability attributes on the type.
QualType desugared = type;
@@ -5881,7 +6038,8 @@ bool Sema::checkNullabilityTypeSpecifier(QualType &type,
}
// If this definitely isn't a pointer type, reject the specifier.
- if (!desugared->canHaveNullability()) {
+ if (!desugared->canHaveNullability() &&
+ !(allowOnArrayType && desugared->isArrayType())) {
Diag(nullabilityLoc, diag::err_nullability_nonpointer)
<< DiagNullabilityKind(nullability, isContextSensitive) << type;
return true;
@@ -5891,7 +6049,12 @@ bool Sema::checkNullabilityTypeSpecifier(QualType &type,
// attributes, require that the type be a single-level pointer.
if (isContextSensitive) {
// Make sure that the pointee isn't itself a pointer type.
- QualType pointeeType = desugared->getPointeeType();
+ const Type *pointeeType;
+ if (desugared->isArrayType())
+ pointeeType = desugared->getArrayElementTypeNoTypeQual();
+ else
+ pointeeType = desugared->getPointeeType().getTypePtr();
+
if (pointeeType->isAnyPointerType() ||
pointeeType->isObjCObjectPointerType() ||
pointeeType->isMemberPointerType()) {
@@ -5914,6 +6077,13 @@ bool Sema::checkNullabilityTypeSpecifier(QualType &type,
}
bool Sema::checkObjCKindOfType(QualType &type, SourceLocation loc) {
+ if (isa<ObjCTypeParamType>(type)) {
+ // Build the attributed type to record where __kindof occurred.
+ type = Context.getAttributedType(AttributedType::attr_objc_kindof,
+ type, type);
+ return false;
+ }
+
// Find out if it's an Objective-C object or object pointer type;
const ObjCObjectPointerType *ptrType = type->getAs<ObjCObjectPointerType>();
const ObjCObjectType *objType = ptrType ? ptrType->getObjectType()
@@ -6070,6 +6240,8 @@ static AttributedType::Kind getCCTypeAttrKind(AttributeList &Attr) {
return AttributedType::attr_stdcall;
case AttributeList::AT_ThisCall:
return AttributedType::attr_thiscall;
+ case AttributeList::AT_RegCall:
+ return AttributedType::attr_regcall;
case AttributeList::AT_Pascal:
return AttributedType::attr_pascal;
case AttributeList::AT_SwiftCall:
@@ -6523,6 +6695,11 @@ static void HandleOpenCLAccessAttr(QualType &CurType, const AttributeList &Attr,
S.Diag(TypedefTy->getDecl()->getLocStart(),
diag::note_opencl_typedef_access_qualifier) << PrevAccessQual;
+ } else if (CurType->isPipeType()) {
+ if (Attr.getSemanticSpelling() == OpenCLAccessAttr::Keyword_write_only) {
+ QualType ElemType = CurType->getAs<PipeType>()->getElementType();
+ CurType = S.Context.getWritePipeType(ElemType);
+ }
}
}
@@ -6637,12 +6814,22 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
// don't want to distribute the nullability specifier past any
// dependent type, because that complicates the user model.
if (type->canHaveNullability() || type->isDependentType() ||
+ type->isArrayType() ||
!distributeNullabilityTypeAttr(state, type, attr)) {
+ unsigned endIndex;
+ if (TAL == TAL_DeclChunk)
+ endIndex = state.getCurrentChunkIndex();
+ else
+ endIndex = state.getDeclarator().getNumTypeObjects();
+ bool allowOnArrayType =
+ state.getDeclarator().isPrototypeContext() &&
+ !hasOuterPointerLikeChunk(state.getDeclarator(), endIndex);
if (state.getSema().checkNullabilityTypeSpecifier(
type,
mapNullabilityAttrKind(attr.getKind()),
attr.getLoc(),
- attr.isContextSensitiveKeywordAttribute())) {
+ attr.isContextSensitiveKeywordAttribute(),
+ allowOnArrayType)) {
attr.setInvalid();
}
@@ -6879,6 +7066,14 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested,
return false;
}
D = ED->getDefinition();
+ } else if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ if (auto *Pattern = FD->getTemplateInstantiationPattern())
+ FD = Pattern;
+ D = FD->getDefinition();
+ } else if (auto *VD = dyn_cast<VarDecl>(D)) {
+ if (auto *Pattern = VD->getTemplateInstantiationPattern())
+ VD = Pattern;
+ D = VD->getDefinition();
}
assert(D && "missing definition for pattern of instantiated definition");
@@ -6886,7 +7081,7 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested,
if (isVisible(D))
return true;
- // The external source may have additional definitions of this type that are
+ // The external source may have additional definitions of this entity that are
// visible, so complete the redeclaration chain now and ask again.
if (auto *Source = Context.getExternalSource()) {
Source->CompleteRedeclChain(D);