| //===--- SemaType.cpp - Semantic Analysis for Types -----------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements type-related semantic analysis. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "TypeLocBuilder.h" |
| #include "clang/AST/ASTConsumer.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/ASTMutationListener.h" |
| #include "clang/AST/ASTStructuralEquivalence.h" |
| #include "clang/AST/CXXInheritance.h" |
| #include "clang/AST/DeclObjC.h" |
| #include "clang/AST/DeclTemplate.h" |
| #include "clang/AST/Expr.h" |
| #include "clang/AST/TypeLoc.h" |
| #include "clang/AST/TypeLocVisitor.h" |
| #include "clang/Basic/PartialDiagnostic.h" |
| #include "clang/Basic/TargetInfo.h" |
| #include "clang/Lex/Preprocessor.h" |
| #include "clang/Sema/DeclSpec.h" |
| #include "clang/Sema/DelayedDiagnostic.h" |
| #include "clang/Sema/Lookup.h" |
| #include "clang/Sema/ScopeInfo.h" |
| #include "clang/Sema/SemaInternal.h" |
| #include "clang/Sema/Template.h" |
| #include "clang/Sema/TemplateInstCallback.h" |
| #include "llvm/ADT/SmallPtrSet.h" |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/ADT/StringSwitch.h" |
| #include "llvm/Support/ErrorHandling.h" |
| |
| using namespace clang; |
| |
| enum TypeDiagSelector { |
| TDS_Function, |
| TDS_Pointer, |
| TDS_ObjCObjOrBlock |
| }; |
| |
| /// isOmittedBlockReturnType - Return true if this declarator is missing a |
| /// return type because this is a omitted return type on a block literal. |
| static bool isOmittedBlockReturnType(const Declarator &D) { |
| if (D.getContext() != DeclaratorContext::BlockLiteralContext || |
| D.getDeclSpec().hasTypeSpecifier()) |
| return false; |
| |
| if (D.getNumTypeObjects() == 0) |
| return true; // ^{ ... } |
| |
| if (D.getNumTypeObjects() == 1 && |
| D.getTypeObject(0).Kind == DeclaratorChunk::Function) |
| return true; // ^(int X, float Y) { ... } |
| |
| return false; |
| } |
| |
| /// diagnoseBadTypeAttribute - Diagnoses a type attribute which |
| /// doesn't apply to the given type. |
| static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr, |
| QualType type) { |
| TypeDiagSelector WhichType; |
| bool useExpansionLoc = true; |
| switch (attr.getKind()) { |
| case ParsedAttr::AT_ObjCGC: |
| WhichType = TDS_Pointer; |
| break; |
| case ParsedAttr::AT_ObjCOwnership: |
| WhichType = TDS_ObjCObjOrBlock; |
| break; |
| default: |
| // Assume everything else was a function attribute. |
| WhichType = TDS_Function; |
| useExpansionLoc = false; |
| break; |
| } |
| |
| SourceLocation loc = attr.getLoc(); |
| 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 |
| : nullptr; |
| if (useExpansionLoc && loc.isMacroID() && II) { |
| if (II->isStr("strong")) { |
| if (S.findMacroSpelling(loc, "__strong")) name = "__strong"; |
| } else if (II->isStr("weak")) { |
| if (S.findMacroSpelling(loc, "__weak")) name = "__weak"; |
| } |
| } |
| |
| S.Diag(loc, diag::warn_type_attribute_wrong_type) << name << WhichType |
| << type; |
| } |
| |
| // objc_gc applies to Objective-C pointers or, otherwise, to the |
| // smallest available pointer type (i.e. 'void*' in 'void**'). |
| #define OBJC_POINTER_TYPE_ATTRS_CASELIST \ |
| case ParsedAttr::AT_ObjCGC: \ |
| case ParsedAttr::AT_ObjCOwnership |
| |
| // Calling convention attributes. |
| #define CALLING_CONV_ATTRS_CASELIST \ |
| case ParsedAttr::AT_CDecl: \ |
| case ParsedAttr::AT_FastCall: \ |
| case ParsedAttr::AT_StdCall: \ |
| case ParsedAttr::AT_ThisCall: \ |
| case ParsedAttr::AT_RegCall: \ |
| case ParsedAttr::AT_Pascal: \ |
| case ParsedAttr::AT_SwiftCall: \ |
| case ParsedAttr::AT_VectorCall: \ |
| case ParsedAttr::AT_AArch64VectorPcs: \ |
| case ParsedAttr::AT_MSABI: \ |
| case ParsedAttr::AT_SysVABI: \ |
| case ParsedAttr::AT_Pcs: \ |
| case ParsedAttr::AT_IntelOclBicc: \ |
| case ParsedAttr::AT_PreserveMost: \ |
| case ParsedAttr::AT_PreserveAll |
| |
| // Function type attributes. |
| #define FUNCTION_TYPE_ATTRS_CASELIST \ |
| case ParsedAttr::AT_NSReturnsRetained: \ |
| case ParsedAttr::AT_NoReturn: \ |
| case ParsedAttr::AT_Regparm: \ |
| case ParsedAttr::AT_AnyX86NoCallerSavedRegisters: \ |
| case ParsedAttr::AT_AnyX86NoCfCheck: \ |
| CALLING_CONV_ATTRS_CASELIST |
| |
| // Microsoft-specific type qualifiers. |
| #define MS_TYPE_ATTRS_CASELIST \ |
| case ParsedAttr::AT_Ptr32: \ |
| case ParsedAttr::AT_Ptr64: \ |
| case ParsedAttr::AT_SPtr: \ |
| case ParsedAttr::AT_UPtr |
| |
| // Nullability qualifiers. |
| #define NULLABILITY_TYPE_ATTRS_CASELIST \ |
| case ParsedAttr::AT_TypeNonNull: \ |
| case ParsedAttr::AT_TypeNullable: \ |
| case ParsedAttr::AT_TypeNullUnspecified |
| |
| namespace { |
| /// An object which stores processing state for the entire |
| /// GetTypeForDeclarator process. |
| class TypeProcessingState { |
| Sema &sema; |
| |
| /// The declarator being processed. |
| Declarator &declarator; |
| |
| /// The index of the declarator chunk we're currently processing. |
| /// May be the total number of valid chunks, indicating the |
| /// DeclSpec. |
| unsigned chunkIndex; |
| |
| /// Whether there are non-trivial modifications to the decl spec. |
| bool trivial; |
| |
| /// Whether we saved the attributes in the decl spec. |
| bool hasSavedAttrs; |
| |
| /// The original set of attributes on the DeclSpec. |
| SmallVector<ParsedAttr *, 2> savedAttrs; |
| |
| /// A list of attributes to diagnose the uselessness of when the |
| /// processing is complete. |
| SmallVector<ParsedAttr *, 2> ignoredTypeAttrs; |
| |
| /// Attributes corresponding to AttributedTypeLocs that we have not yet |
| /// populated. |
| // FIXME: The two-phase mechanism by which we construct Types and fill |
| // their TypeLocs makes it hard to correctly assign these. We keep the |
| // attributes in creation order as an attempt to make them line up |
| // properly. |
| using TypeAttrPair = std::pair<const AttributedType*, const Attr*>; |
| SmallVector<TypeAttrPair, 8> AttrsForTypes; |
| bool AttrsForTypesSorted = true; |
| |
| /// MacroQualifiedTypes mapping to macro expansion locations that will be |
| /// stored in a MacroQualifiedTypeLoc. |
| llvm::DenseMap<const MacroQualifiedType *, SourceLocation> LocsForMacros; |
| |
| /// Flag to indicate we parsed a noderef attribute. This is used for |
| /// validating that noderef was used on a pointer or array. |
| bool parsedNoDeref; |
| |
| public: |
| TypeProcessingState(Sema &sema, Declarator &declarator) |
| : sema(sema), declarator(declarator), |
| chunkIndex(declarator.getNumTypeObjects()), trivial(true), |
| hasSavedAttrs(false), parsedNoDeref(false) {} |
| |
| Sema &getSema() const { |
| return sema; |
| } |
| |
| Declarator &getDeclarator() const { |
| return declarator; |
| } |
| |
| bool isProcessingDeclSpec() const { |
| return chunkIndex == declarator.getNumTypeObjects(); |
| } |
| |
| unsigned getCurrentChunkIndex() const { |
| return chunkIndex; |
| } |
| |
| void setCurrentChunkIndex(unsigned idx) { |
| assert(idx <= declarator.getNumTypeObjects()); |
| chunkIndex = idx; |
| } |
| |
| ParsedAttributesView &getCurrentAttributes() const { |
| if (isProcessingDeclSpec()) |
| return getMutableDeclSpec().getAttributes(); |
| return declarator.getTypeObject(chunkIndex).getAttrs(); |
| } |
| |
| /// Save the current set of attributes on the DeclSpec. |
| void saveDeclSpecAttrs() { |
| // Don't try to save them multiple times. |
| if (hasSavedAttrs) return; |
| |
| DeclSpec &spec = getMutableDeclSpec(); |
| for (ParsedAttr &AL : spec.getAttributes()) |
| savedAttrs.push_back(&AL); |
| trivial &= savedAttrs.empty(); |
| hasSavedAttrs = true; |
| } |
| |
| /// Record that we had nowhere to put the given type attribute. |
| /// We will diagnose such attributes later. |
| void addIgnoredTypeAttr(ParsedAttr &attr) { |
| ignoredTypeAttrs.push_back(&attr); |
| } |
| |
| /// Diagnose all the ignored type attributes, given that the |
| /// declarator worked out to the given type. |
| void diagnoseIgnoredTypeAttrs(QualType type) const { |
| for (auto *Attr : ignoredTypeAttrs) |
| diagnoseBadTypeAttribute(getSema(), *Attr, type); |
| } |
| |
| /// Get an attributed type for the given attribute, and remember the Attr |
| /// object so that we can attach it to the AttributedTypeLoc. |
| QualType getAttributedType(Attr *A, QualType ModifiedType, |
| QualType EquivType) { |
| QualType T = |
| sema.Context.getAttributedType(A->getKind(), ModifiedType, EquivType); |
| AttrsForTypes.push_back({cast<AttributedType>(T.getTypePtr()), A}); |
| AttrsForTypesSorted = false; |
| return T; |
| } |
| |
| /// Completely replace the \c auto in \p TypeWithAuto by |
| /// \p Replacement. Also replace \p TypeWithAuto in \c TypeAttrPair if |
| /// necessary. |
| QualType ReplaceAutoType(QualType TypeWithAuto, QualType Replacement) { |
| QualType T = sema.ReplaceAutoType(TypeWithAuto, Replacement); |
| if (auto *AttrTy = TypeWithAuto->getAs<AttributedType>()) { |
| // Attributed type still should be an attributed type after replacement. |
| auto *NewAttrTy = cast<AttributedType>(T.getTypePtr()); |
| for (TypeAttrPair &A : AttrsForTypes) { |
| if (A.first == AttrTy) |
| A.first = NewAttrTy; |
| } |
| AttrsForTypesSorted = false; |
| } |
| return T; |
| } |
| |
| /// Extract and remove the Attr* for a given attributed type. |
| const Attr *takeAttrForAttributedType(const AttributedType *AT) { |
| if (!AttrsForTypesSorted) { |
| llvm::stable_sort(AttrsForTypes, llvm::less_first()); |
| AttrsForTypesSorted = true; |
| } |
| |
| // FIXME: This is quadratic if we have lots of reuses of the same |
| // attributed type. |
| for (auto It = std::partition_point( |
| AttrsForTypes.begin(), AttrsForTypes.end(), |
| [=](const TypeAttrPair &A) { return A.first < AT; }); |
| It != AttrsForTypes.end() && It->first == AT; ++It) { |
| if (It->second) { |
| const Attr *Result = It->second; |
| It->second = nullptr; |
| return Result; |
| } |
| } |
| |
| llvm_unreachable("no Attr* for AttributedType*"); |
| } |
| |
| SourceLocation |
| getExpansionLocForMacroQualifiedType(const MacroQualifiedType *MQT) const { |
| auto FoundLoc = LocsForMacros.find(MQT); |
| assert(FoundLoc != LocsForMacros.end() && |
| "Unable to find macro expansion location for MacroQualifedType"); |
| return FoundLoc->second; |
| } |
| |
| void setExpansionLocForMacroQualifiedType(const MacroQualifiedType *MQT, |
| SourceLocation Loc) { |
| LocsForMacros[MQT] = Loc; |
| } |
| |
| void setParsedNoDeref(bool parsed) { parsedNoDeref = parsed; } |
| |
| bool didParseNoDeref() const { return parsedNoDeref; } |
| |
| ~TypeProcessingState() { |
| if (trivial) return; |
| |
| restoreDeclSpecAttrs(); |
| } |
| |
| private: |
| DeclSpec &getMutableDeclSpec() const { |
| return const_cast<DeclSpec&>(declarator.getDeclSpec()); |
| } |
| |
| void restoreDeclSpecAttrs() { |
| assert(hasSavedAttrs); |
| |
| getMutableDeclSpec().getAttributes().clearListOnly(); |
| for (ParsedAttr *AL : savedAttrs) |
| getMutableDeclSpec().getAttributes().addAtEnd(AL); |
| } |
| }; |
| } // end anonymous namespace |
| |
| static void moveAttrFromListToList(ParsedAttr &attr, |
| ParsedAttributesView &fromList, |
| ParsedAttributesView &toList) { |
| fromList.remove(&attr); |
| toList.addAtEnd(&attr); |
| } |
| |
| /// The location of a type attribute. |
| enum TypeAttrLocation { |
| /// The attribute is in the decl-specifier-seq. |
| TAL_DeclSpec, |
| /// The attribute is part of a DeclaratorChunk. |
| TAL_DeclChunk, |
| /// The attribute is immediately after the declaration's name. |
| TAL_DeclName |
| }; |
| |
| static void processTypeAttrs(TypeProcessingState &state, QualType &type, |
| TypeAttrLocation TAL, ParsedAttributesView &attrs); |
| |
| static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, |
| QualType &type); |
| |
| static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &state, |
| ParsedAttr &attr, QualType &type); |
| |
| static bool handleObjCGCTypeAttr(TypeProcessingState &state, ParsedAttr &attr, |
| QualType &type); |
| |
| static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, |
| ParsedAttr &attr, QualType &type); |
| |
| static bool handleObjCPointerTypeAttr(TypeProcessingState &state, |
| ParsedAttr &attr, QualType &type) { |
| if (attr.getKind() == ParsedAttr::AT_ObjCGC) |
| return handleObjCGCTypeAttr(state, attr, type); |
| assert(attr.getKind() == ParsedAttr::AT_ObjCOwnership); |
| return handleObjCOwnershipTypeAttr(state, attr, type); |
| } |
| |
| /// Given the index of a declarator chunk, check whether that chunk |
| /// directly specifies the return type of a function and, if so, find |
| /// an appropriate place for it. |
| /// |
| /// \param i - a notional index which the search will start |
| /// immediately inside |
| /// |
| /// \param onlyBlockPointers Whether we should only look into block |
| /// pointer types (vs. all pointer types). |
| static DeclaratorChunk *maybeMovePastReturnType(Declarator &declarator, |
| unsigned i, |
| bool onlyBlockPointers) { |
| assert(i <= declarator.getNumTypeObjects()); |
| |
| DeclaratorChunk *result = nullptr; |
| |
| // First, look inwards past parens for a function declarator. |
| for (; i != 0; --i) { |
| DeclaratorChunk &fnChunk = declarator.getTypeObject(i-1); |
| switch (fnChunk.Kind) { |
| case DeclaratorChunk::Paren: |
| continue; |
| |
| // If we find anything except a function, bail out. |
| case DeclaratorChunk::Pointer: |
| case DeclaratorChunk::BlockPointer: |
| case DeclaratorChunk::Array: |
| case DeclaratorChunk::Reference: |
| case DeclaratorChunk::MemberPointer: |
| case DeclaratorChunk::Pipe: |
| return result; |
| |
| // If we do find a function declarator, scan inwards from that, |
| // looking for a (block-)pointer declarator. |
| case DeclaratorChunk::Function: |
| for (--i; i != 0; --i) { |
| DeclaratorChunk &ptrChunk = declarator.getTypeObject(i-1); |
| switch (ptrChunk.Kind) { |
| case DeclaratorChunk::Paren: |
| case DeclaratorChunk::Array: |
| case DeclaratorChunk::Function: |
| case DeclaratorChunk::Reference: |
| case DeclaratorChunk::Pipe: |
| continue; |
| |
| case DeclaratorChunk::MemberPointer: |
| case DeclaratorChunk::Pointer: |
| if (onlyBlockPointers) |
| continue; |
| |
| LLVM_FALLTHROUGH; |
| |
| case DeclaratorChunk::BlockPointer: |
| result = &ptrChunk; |
| goto continue_outer; |
| } |
| llvm_unreachable("bad declarator chunk kind"); |
| } |
| |
| // If we run out of declarators doing that, we're done. |
| return result; |
| } |
| llvm_unreachable("bad declarator chunk kind"); |
| |
| // Okay, reconsider from our new point. |
| continue_outer: ; |
| } |
| |
| // Ran out of chunks, bail out. |
| return result; |
| } |
| |
| /// Given that an objc_gc attribute was written somewhere on a |
| /// declaration *other* than on the declarator itself (for which, use |
| /// distributeObjCPointerTypeAttrFromDeclarator), and given that it |
| /// didn't apply in whatever position it was written in, try to move |
| /// it to a more appropriate position. |
| static void distributeObjCPointerTypeAttr(TypeProcessingState &state, |
| ParsedAttr &attr, QualType type) { |
| Declarator &declarator = state.getDeclarator(); |
| |
| // Move it to the outermost normal or block pointer declarator. |
| for (unsigned i = state.getCurrentChunkIndex(); i != 0; --i) { |
| DeclaratorChunk &chunk = declarator.getTypeObject(i-1); |
| switch (chunk.Kind) { |
| case DeclaratorChunk::Pointer: |
| case DeclaratorChunk::BlockPointer: { |
| // But don't move an ARC ownership attribute to the return type |
| // of a block. |
| DeclaratorChunk *destChunk = nullptr; |
| if (state.isProcessingDeclSpec() && |
| attr.getKind() == ParsedAttr::AT_ObjCOwnership) |
| destChunk = maybeMovePastReturnType(declarator, i - 1, |
| /*onlyBlockPointers=*/true); |
| if (!destChunk) destChunk = &chunk; |
| |
| moveAttrFromListToList(attr, state.getCurrentAttributes(), |
| destChunk->getAttrs()); |
| return; |
| } |
| |
| case DeclaratorChunk::Paren: |
| case DeclaratorChunk::Array: |
| continue; |
| |
| // We may be starting at the return type of a block. |
| case DeclaratorChunk::Function: |
| if (state.isProcessingDeclSpec() && |
| attr.getKind() == ParsedAttr::AT_ObjCOwnership) { |
| if (DeclaratorChunk *dest = maybeMovePastReturnType( |
| declarator, i, |
| /*onlyBlockPointers=*/true)) { |
| moveAttrFromListToList(attr, state.getCurrentAttributes(), |
| dest->getAttrs()); |
| return; |
| } |
| } |
| goto error; |
| |
| // Don't walk through these. |
| case DeclaratorChunk::Reference: |
| case DeclaratorChunk::MemberPointer: |
| case DeclaratorChunk::Pipe: |
| goto error; |
| } |
| } |
| error: |
| |
| diagnoseBadTypeAttribute(state.getSema(), attr, type); |
| } |
| |
| /// Distribute an objc_gc type attribute that was written on the |
| /// declarator. |
| static void distributeObjCPointerTypeAttrFromDeclarator( |
| TypeProcessingState &state, ParsedAttr &attr, QualType &declSpecType) { |
| Declarator &declarator = state.getDeclarator(); |
| |
| // objc_gc goes on the innermost pointer to something that's not a |
| // pointer. |
| unsigned innermost = -1U; |
| bool considerDeclSpec = true; |
| for (unsigned i = 0, e = declarator.getNumTypeObjects(); i != e; ++i) { |
| DeclaratorChunk &chunk = declarator.getTypeObject(i); |
| switch (chunk.Kind) { |
| case DeclaratorChunk::Pointer: |
| case DeclaratorChunk::BlockPointer: |
| innermost = i; |
| continue; |
| |
| case DeclaratorChunk::Reference: |
| case DeclaratorChunk::MemberPointer: |
| case DeclaratorChunk::Paren: |
| case DeclaratorChunk::Array: |
| case DeclaratorChunk::Pipe: |
| continue; |
| |
| case DeclaratorChunk::Function: |
| considerDeclSpec = false; |
| goto done; |
| } |
| } |
| done: |
| |
| // That might actually be the decl spec if we weren't blocked by |
| // anything in the declarator. |
| if (considerDeclSpec) { |
| if (handleObjCPointerTypeAttr(state, attr, declSpecType)) { |
| // Splice the attribute into the decl spec. Prevents the |
| // attribute from being applied multiple times and gives |
| // the source-location-filler something to work with. |
| state.saveDeclSpecAttrs(); |
| declarator.getMutableDeclSpec().getAttributes().takeOneFrom( |
| declarator.getAttributes(), &attr); |
| return; |
| } |
| } |
| |
| // Otherwise, if we found an appropriate chunk, splice the attribute |
| // into it. |
| if (innermost != -1U) { |
| moveAttrFromListToList(attr, declarator.getAttributes(), |
| declarator.getTypeObject(innermost).getAttrs()); |
| return; |
| } |
| |
| // Otherwise, diagnose when we're done building the type. |
| declarator.getAttributes().remove(&attr); |
| state.addIgnoredTypeAttr(attr); |
| } |
| |
| /// A function type attribute was written somewhere in a declaration |
| /// *other* than on the declarator itself or in the decl spec. Given |
| /// that it didn't apply in whatever position it was written in, try |
| /// to move it to a more appropriate position. |
| static void distributeFunctionTypeAttr(TypeProcessingState &state, |
| ParsedAttr &attr, QualType type) { |
| Declarator &declarator = state.getDeclarator(); |
| |
| // Try to push the attribute from the return type of a function to |
| // the function itself. |
| for (unsigned i = state.getCurrentChunkIndex(); i != 0; --i) { |
| DeclaratorChunk &chunk = declarator.getTypeObject(i-1); |
| switch (chunk.Kind) { |
| case DeclaratorChunk::Function: |
| moveAttrFromListToList(attr, state.getCurrentAttributes(), |
| chunk.getAttrs()); |
| return; |
| |
| case DeclaratorChunk::Paren: |
| case DeclaratorChunk::Pointer: |
| case DeclaratorChunk::BlockPointer: |
| case DeclaratorChunk::Array: |
| case DeclaratorChunk::Reference: |
| case DeclaratorChunk::MemberPointer: |
| case DeclaratorChunk::Pipe: |
| continue; |
| } |
| } |
| |
| diagnoseBadTypeAttribute(state.getSema(), attr, type); |
| } |
| |
| /// Try to distribute a function type attribute to the innermost |
| /// function chunk or type. Returns true if the attribute was |
| /// distributed, false if no location was found. |
| static bool distributeFunctionTypeAttrToInnermost( |
| TypeProcessingState &state, ParsedAttr &attr, |
| ParsedAttributesView &attrList, QualType &declSpecType) { |
| Declarator &declarator = state.getDeclarator(); |
| |
| // Put it on the innermost function chunk, if there is one. |
| for (unsigned i = 0, e = declarator.getNumTypeObjects(); i != e; ++i) { |
| DeclaratorChunk &chunk = declarator.getTypeObject(i); |
| if (chunk.Kind != DeclaratorChunk::Function) continue; |
| |
| moveAttrFromListToList(attr, attrList, chunk.getAttrs()); |
| return true; |
| } |
| |
| return handleFunctionTypeAttr(state, attr, declSpecType); |
| } |
| |
| /// A function type attribute was written in the decl spec. Try to |
| /// apply it somewhere. |
| static void distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state, |
| ParsedAttr &attr, |
| QualType &declSpecType) { |
| state.saveDeclSpecAttrs(); |
| |
| // C++11 attributes before the decl specifiers actually appertain to |
| // the declarators. Move them straight there. We don't support the |
| // 'put them wherever you like' semantics we allow for GNU attributes. |
| if (attr.isCXX11Attribute()) { |
| moveAttrFromListToList(attr, state.getCurrentAttributes(), |
| state.getDeclarator().getAttributes()); |
| return; |
| } |
| |
| // Try to distribute to the innermost. |
| if (distributeFunctionTypeAttrToInnermost( |
| state, attr, state.getCurrentAttributes(), declSpecType)) |
| return; |
| |
| // If that failed, diagnose the bad attribute when the declarator is |
| // fully built. |
| state.addIgnoredTypeAttr(attr); |
| } |
| |
| /// A function type attribute was written on the declarator. Try to |
| /// apply it somewhere. |
| static void distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state, |
| ParsedAttr &attr, |
| QualType &declSpecType) { |
| Declarator &declarator = state.getDeclarator(); |
| |
| // Try to distribute to the innermost. |
| if (distributeFunctionTypeAttrToInnermost( |
| state, attr, declarator.getAttributes(), declSpecType)) |
| return; |
| |
| // If that failed, diagnose the bad attribute when the declarator is |
| // fully built. |
| declarator.getAttributes().remove(&attr); |
| state.addIgnoredTypeAttr(attr); |
| } |
| |
| /// Given that there are attributes written on the declarator |
| /// itself, try to distribute any type attributes to the appropriate |
| /// declarator chunk. |
| /// |
| /// These are attributes like the following: |
| /// int f ATTR; |
| /// int (f ATTR)(); |
| /// but not necessarily this: |
| /// int f() ATTR; |
| static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state, |
| QualType &declSpecType) { |
| // Collect all the type attributes from the declarator itself. |
| assert(!state.getDeclarator().getAttributes().empty() && |
| "declarator has no attrs!"); |
| // The called functions in this loop actually remove things from the current |
| // list, so iterating over the existing list isn't possible. Instead, make a |
| // non-owning copy and iterate over that. |
| ParsedAttributesView AttrsCopy{state.getDeclarator().getAttributes()}; |
| for (ParsedAttr &attr : AttrsCopy) { |
| // Do not distribute C++11 attributes. They have strict rules for what |
| // they appertain to. |
| if (attr.isCXX11Attribute()) |
| continue; |
| |
| switch (attr.getKind()) { |
| OBJC_POINTER_TYPE_ATTRS_CASELIST: |
| distributeObjCPointerTypeAttrFromDeclarator(state, attr, declSpecType); |
| break; |
| |
| FUNCTION_TYPE_ATTRS_CASELIST: |
| distributeFunctionTypeAttrFromDeclarator(state, attr, declSpecType); |
| break; |
| |
| MS_TYPE_ATTRS_CASELIST: |
| // Microsoft type attributes cannot go after the declarator-id. |
| continue; |
| |
| NULLABILITY_TYPE_ATTRS_CASELIST: |
| // Nullability specifiers cannot go after the declarator-id. |
| |
| // Objective-C __kindof does not get distributed. |
| case ParsedAttr::AT_ObjCKindOf: |
| continue; |
| |
| default: |
| break; |
| } |
| } |
| } |
| |
| /// Add a synthetic '()' to a block-literal declarator if it is |
| /// required, given the return type. |
| static void maybeSynthesizeBlockSignature(TypeProcessingState &state, |
| QualType declSpecType) { |
| Declarator &declarator = state.getDeclarator(); |
| |
| // First, check whether the declarator would produce a function, |
| // i.e. whether the innermost semantic chunk is a function. |
| if (declarator.isFunctionDeclarator()) { |
| // If so, make that declarator a prototyped declarator. |
| declarator.getFunctionTypeInfo().hasPrototype = true; |
| return; |
| } |
| |
| // If there are any type objects, the type as written won't name a |
| // function, regardless of the decl spec type. This is because a |
| // block signature declarator is always an abstract-declarator, and |
| // abstract-declarators can't just be parentheses chunks. Therefore |
| // we need to build a function chunk unless there are no type |
| // objects and the decl spec type is a function. |
| if (!declarator.getNumTypeObjects() && declSpecType->isFunctionType()) |
| return; |
| |
| // Note that there *are* cases with invalid declarators where |
| // declarators consist solely of parentheses. In general, these |
| // occur only in failed efforts to make function declarators, so |
| // faking up the function chunk is still the right thing to do. |
| |
| // Otherwise, we need to fake up a function declarator. |
| SourceLocation loc = declarator.getBeginLoc(); |
| |
| // ...and *prepend* it to the declarator. |
| SourceLocation NoLoc; |
| declarator.AddInnermostTypeInfo(DeclaratorChunk::getFunction( |
| /*HasProto=*/true, |
| /*IsAmbiguous=*/false, |
| /*LParenLoc=*/NoLoc, |
| /*ArgInfo=*/nullptr, |
| /*NumParams=*/0, |
| /*EllipsisLoc=*/NoLoc, |
| /*RParenLoc=*/NoLoc, |
| /*RefQualifierIsLvalueRef=*/true, |
| /*RefQualifierLoc=*/NoLoc, |
| /*MutableLoc=*/NoLoc, EST_None, |
| /*ESpecRange=*/SourceRange(), |
| /*Exceptions=*/nullptr, |
| /*ExceptionRanges=*/nullptr, |
| /*NumExceptions=*/0, |
| /*NoexceptExpr=*/nullptr, |
| /*ExceptionSpecTokens=*/nullptr, |
| /*DeclsInPrototype=*/None, loc, loc, declarator)); |
| |
| // For consistency, make sure the state still has us as processing |
| // the decl spec. |
| assert(state.getCurrentChunkIndex() == declarator.getNumTypeObjects() - 1); |
| state.setCurrentChunkIndex(declarator.getNumTypeObjects()); |
| } |
| |
| static void diagnoseAndRemoveTypeQualifiers(Sema &S, const DeclSpec &DS, |
| unsigned &TypeQuals, |
| QualType TypeSoFar, |
| unsigned RemoveTQs, |
| unsigned DiagID) { |
| // If this occurs outside a template instantiation, warn the user about |
| // it; they probably didn't mean to specify a redundant qualifier. |
| typedef std::pair<DeclSpec::TQ, SourceLocation> QualLoc; |
| for (QualLoc Qual : {QualLoc(DeclSpec::TQ_const, DS.getConstSpecLoc()), |
| QualLoc(DeclSpec::TQ_restrict, DS.getRestrictSpecLoc()), |
| QualLoc(DeclSpec::TQ_volatile, DS.getVolatileSpecLoc()), |
| QualLoc(DeclSpec::TQ_atomic, DS.getAtomicSpecLoc())}) { |
| if (!(RemoveTQs & Qual.first)) |
| continue; |
| |
| if (!S.inTemplateInstantiation()) { |
| if (TypeQuals & Qual.first) |
| S.Diag(Qual.second, DiagID) |
| << DeclSpec::getSpecifierName(Qual.first) << TypeSoFar |
| << FixItHint::CreateRemoval(Qual.second); |
| } |
| |
| TypeQuals &= ~Qual.first; |
| } |
| } |
| |
| /// Return true if this is omitted block return type. Also check type |
| /// attributes and type qualifiers when returning true. |
| static bool checkOmittedBlockReturnType(Sema &S, Declarator &declarator, |
| QualType Result) { |
| if (!isOmittedBlockReturnType(declarator)) |
| return false; |
| |
| // Warn if we see type attributes for omitted return type on a block literal. |
| SmallVector<ParsedAttr *, 2> ToBeRemoved; |
| for (ParsedAttr &AL : declarator.getMutableDeclSpec().getAttributes()) { |
| if (AL.isInvalid() || !AL.isTypeAttr()) |
| continue; |
| S.Diag(AL.getLoc(), |
| diag::warn_block_literal_attributes_on_omitted_return_type) |
| << AL; |
| ToBeRemoved.push_back(&AL); |
| } |
| // Remove bad attributes from the list. |
| for (ParsedAttr *AL : ToBeRemoved) |
| declarator.getMutableDeclSpec().getAttributes().remove(AL); |
| |
| // Warn if we see type qualifiers for omitted return type on a block literal. |
| const DeclSpec &DS = declarator.getDeclSpec(); |
| unsigned TypeQuals = DS.getTypeQualifiers(); |
| diagnoseAndRemoveTypeQualifiers(S, DS, TypeQuals, Result, (unsigned)-1, |
| diag::warn_block_literal_qualifiers_on_omitted_return_type); |
| declarator.getMutableDeclSpec().ClearTypeQualifiers(); |
| |
| return true; |
| } |
| |
| /// Apply Objective-C type arguments to the given type. |
| static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type, |
| ArrayRef<TypeSourceInfo *> typeArgs, |
| SourceRange typeArgsRange, |
| bool failOnError = false) { |
| // We can only apply type arguments to an Objective-C class type. |
| const auto *objcObjectType = type->getAs<ObjCObjectType>(); |
| if (!objcObjectType || !objcObjectType->getInterface()) { |
| S.Diag(loc, diag::err_objc_type_args_non_class) |
| << type |
| << typeArgsRange; |
| |
| if (failOnError) |
| return QualType(); |
| return type; |
| } |
| |
| // The class type must be parameterized. |
| ObjCInterfaceDecl *objcClass = objcObjectType->getInterface(); |
| ObjCTypeParamList *typeParams = objcClass->getTypeParamList(); |
| if (!typeParams) { |
| S.Diag(loc, diag::err_objc_type_args_non_parameterized_class) |
| << objcClass->getDeclName() |
| << FixItHint::CreateRemoval(typeArgsRange); |
| |
| if (failOnError) |
| return QualType(); |
| |
| return type; |
| } |
| |
| // The type must not already be specialized. |
| if (objcObjectType->isSpecialized()) { |
| S.Diag(loc, diag::err_objc_type_args_specialized_class) |
| << type |
| << FixItHint::CreateRemoval(typeArgsRange); |
| |
| if (failOnError) |
| return QualType(); |
| |
| return type; |
| } |
| |
| // Check the type arguments. |
| SmallVector<QualType, 4> finalTypeArgs; |
| unsigned numTypeParams = typeParams->size(); |
| bool anyPackExpansions = false; |
| for (unsigned i = 0, n = typeArgs.size(); i != n; ++i) { |
| TypeSourceInfo *typeArgInfo = typeArgs[i]; |
| QualType typeArg = typeArgInfo->getType(); |
| |
| // Type arguments cannot have explicit qualifiers or nullability. |
| // We ignore indirect sources of these, e.g. behind typedefs or |
| // template arguments. |
| if (TypeLoc qual = typeArgInfo->getTypeLoc().findExplicitQualifierLoc()) { |
| bool diagnosed = false; |
| SourceRange rangeToRemove; |
| if (auto attr = qual.getAs<AttributedTypeLoc>()) { |
| rangeToRemove = attr.getLocalSourceRange(); |
| if (attr.getTypePtr()->getImmediateNullability()) { |
| typeArg = attr.getTypePtr()->getModifiedType(); |
| S.Diag(attr.getBeginLoc(), |
| diag::err_objc_type_arg_explicit_nullability) |
| << typeArg << FixItHint::CreateRemoval(rangeToRemove); |
| diagnosed = true; |
| } |
| } |
| |
| if (!diagnosed) { |
| S.Diag(qual.getBeginLoc(), diag::err_objc_type_arg_qualified) |
| << typeArg << typeArg.getQualifiers().getAsString() |
| << FixItHint::CreateRemoval(rangeToRemove); |
| } |
| } |
| |
| // Remove qualifiers even if they're non-local. |
| typeArg = typeArg.getUnqualifiedType(); |
| |
| finalTypeArgs.push_back(typeArg); |
| |
| if (typeArg->getAs<PackExpansionType>()) |
| anyPackExpansions = true; |
| |
| // Find the corresponding type parameter, if there is one. |
| ObjCTypeParamDecl *typeParam = nullptr; |
| if (!anyPackExpansions) { |
| if (i < numTypeParams) { |
| typeParam = typeParams->begin()[i]; |
| } else { |
| // Too many arguments. |
| S.Diag(loc, diag::err_objc_type_args_wrong_arity) |
| << false |
| << objcClass->getDeclName() |
| << (unsigned)typeArgs.size() |
| << numTypeParams; |
| S.Diag(objcClass->getLocation(), diag::note_previous_decl) |
| << objcClass; |
| |
| if (failOnError) |
| return QualType(); |
| |
| return type; |
| } |
| } |
| |
| // Objective-C object pointer types must be substitutable for the bounds. |
| if (const auto *typeArgObjC = typeArg->getAs<ObjCObjectPointerType>()) { |
| // If we don't have a type parameter to match against, assume |
| // everything is fine. There was a prior pack expansion that |
| // means we won't be able to match anything. |
| if (!typeParam) { |
| assert(anyPackExpansions && "Too many arguments?"); |
| continue; |
| } |
| |
| // Retrieve the bound. |
| QualType bound = typeParam->getUnderlyingType(); |
| const auto *boundObjC = bound->getAs<ObjCObjectPointerType>(); |
| |
| // Determine whether the type argument is substitutable for the bound. |
| if (typeArgObjC->isObjCIdType()) { |
| // When the type argument is 'id', the only acceptable type |
| // parameter bound is 'id'. |
| if (boundObjC->isObjCIdType()) |
| continue; |
| } else if (S.Context.canAssignObjCInterfaces(boundObjC, typeArgObjC)) { |
| // Otherwise, we follow the assignability rules. |
| continue; |
| } |
| |
| // Diagnose the mismatch. |
| S.Diag(typeArgInfo->getTypeLoc().getBeginLoc(), |
| diag::err_objc_type_arg_does_not_match_bound) |
| << typeArg << bound << typeParam->getDeclName(); |
| S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here) |
| << typeParam->getDeclName(); |
| |
| if (failOnError) |
| return QualType(); |
| |
| return type; |
| } |
| |
| // Block pointer types are permitted for unqualified 'id' bounds. |
| if (typeArg->isBlockPointerType()) { |
| // If we don't have a type parameter to match against, assume |
| // everything is fine. There was a prior pack expansion that |
| // means we won't be able to match anything. |
| if (!typeParam) { |
| assert(anyPackExpansions && "Too many arguments?"); |
| continue; |
| } |
| |
| // Retrieve the bound. |
| QualType bound = typeParam->getUnderlyingType(); |
| if (bound->isBlockCompatibleObjCPointerType(S.Context)) |
| continue; |
| |
| // Diagnose the mismatch. |
| S.Diag(typeArgInfo->getTypeLoc().getBeginLoc(), |
| diag::err_objc_type_arg_does_not_match_bound) |
| << typeArg << bound << typeParam->getDeclName(); |
| S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here) |
| << typeParam->getDeclName(); |
| |
| if (failOnError) |
| return QualType(); |
| |
| return type; |
| } |
| |
| // Dependent types will be checked at instantiation time. |
| if (typeArg->isDependentType()) { |
| continue; |
| } |
| |
| // Diagnose non-id-compatible type arguments. |
| S.Diag(typeArgInfo->getTypeLoc().getBeginLoc(), |
| diag::err_objc_type_arg_not_id_compatible) |
| << typeArg << typeArgInfo->getTypeLoc().getSourceRange(); |
| |
| if (failOnError) |
| return QualType(); |
| |
| return type; |
| } |
| |
| // Make sure we didn't have the wrong number of arguments. |
| if (!anyPackExpansions && finalTypeArgs.size() != numTypeParams) { |
| S.Diag(loc, diag::err_objc_type_args_wrong_arity) |
| << (typeArgs.size() < typeParams->size()) |
| << objcClass->getDeclName() |
| << (unsigned)finalTypeArgs.size() |
| << (unsigned)numTypeParams; |
| S.Diag(objcClass->getLocation(), diag::note_previous_decl) |
| << objcClass; |
| |
| if (failOnError) |
| return QualType(); |
| |
| return type; |
| } |
| |
| // Success. Form the specialized type. |
| return S.Context.getObjCObjectType(type, finalTypeArgs, { }, false); |
| } |
| |
| 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(); |
| } |
| |
| return Result; |
| } |
| |
| QualType Sema::BuildObjCObjectType(QualType BaseType, |
| SourceLocation Loc, |
| SourceLocation TypeArgsLAngleLoc, |
| ArrayRef<TypeSourceInfo *> TypeArgs, |
| SourceLocation TypeArgsRAngleLoc, |
| SourceLocation ProtocolLAngleLoc, |
| ArrayRef<ObjCProtocolDecl *> Protocols, |
| ArrayRef<SourceLocation> ProtocolLocs, |
| SourceLocation ProtocolRAngleLoc, |
| bool FailOnError) { |
| QualType Result = BaseType; |
| if (!TypeArgs.empty()) { |
| Result = applyObjCTypeArgs(*this, Loc, Result, TypeArgs, |
| SourceRange(TypeArgsLAngleLoc, |
| TypeArgsRAngleLoc), |
| FailOnError); |
| if (FailOnError && Result.isNull()) |
| return QualType(); |
| } |
| |
| if (!Protocols.empty()) { |
| 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(); |
| } |
| |
| return Result; |
| } |
| |
| TypeResult Sema::actOnObjCProtocolQualifierType( |
| SourceLocation lAngleLoc, |
| ArrayRef<Decl *> protocols, |
| ArrayRef<SourceLocation> protocolLocs, |
| SourceLocation rAngleLoc) { |
| // Form id<protocol-list>. |
| QualType Result = Context.getObjCObjectType( |
| Context.ObjCBuiltinIdTy, { }, |
| llvm::makeArrayRef( |
| (ObjCProtocolDecl * const *)protocols.data(), |
| protocols.size()), |
| false); |
| Result = Context.getObjCObjectPointerType(Result); |
| |
| TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result); |
| TypeLoc ResultTL = ResultTInfo->getTypeLoc(); |
| |
| auto ObjCObjectPointerTL = ResultTL.castAs<ObjCObjectPointerTypeLoc>(); |
| ObjCObjectPointerTL.setStarLoc(SourceLocation()); // implicit |
| |
| auto ObjCObjectTL = ObjCObjectPointerTL.getPointeeLoc() |
| .castAs<ObjCObjectTypeLoc>(); |
| ObjCObjectTL.setHasBaseTypeAsWritten(false); |
| ObjCObjectTL.getBaseLoc().initialize(Context, SourceLocation()); |
| |
| // No type arguments. |
| ObjCObjectTL.setTypeArgsLAngleLoc(SourceLocation()); |
| ObjCObjectTL.setTypeArgsRAngleLoc(SourceLocation()); |
| |
| // Fill in protocol qualifiers. |
| ObjCObjectTL.setProtocolLAngleLoc(lAngleLoc); |
| ObjCObjectTL.setProtocolRAngleLoc(rAngleLoc); |
| for (unsigned i = 0, n = protocols.size(); i != n; ++i) |
| ObjCObjectTL.setProtocolLoc(i, protocolLocs[i]); |
| |
| // We're done. Return the completed type to the parser. |
| return CreateParsedType(Result, ResultTInfo); |
| } |
| |
| TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers( |
| Scope *S, |
| SourceLocation Loc, |
| ParsedType BaseType, |
| SourceLocation TypeArgsLAngleLoc, |
| ArrayRef<ParsedType> TypeArgs, |
| SourceLocation TypeArgsRAngleLoc, |
| SourceLocation ProtocolLAngleLoc, |
| ArrayRef<Decl *> Protocols, |
| ArrayRef<SourceLocation> ProtocolLocs, |
| SourceLocation ProtocolRAngleLoc) { |
| TypeSourceInfo *BaseTypeInfo = nullptr; |
| QualType T = GetTypeFromParser(BaseType, &BaseTypeInfo); |
| if (T.isNull()) |
| return true; |
| |
| // Handle missing type-source info. |
| if (!BaseTypeInfo) |
| BaseTypeInfo = Context.getTrivialTypeSourceInfo(T, Loc); |
| |
| // Extract type arguments. |
| SmallVector<TypeSourceInfo *, 4> ActualTypeArgInfos; |
| for (unsigned i = 0, n = TypeArgs.size(); i != n; ++i) { |
| TypeSourceInfo *TypeArgInfo = nullptr; |
| QualType TypeArg = GetTypeFromParser(TypeArgs[i], &TypeArgInfo); |
| if (TypeArg.isNull()) { |
| ActualTypeArgInfos.clear(); |
| break; |
| } |
| |
| assert(TypeArgInfo && "No type source info?"); |
| ActualTypeArgInfos.push_back(TypeArgInfo); |
| } |
| |
| // Build the object type. |
| QualType Result = BuildObjCObjectType( |
| T, BaseTypeInfo->getTypeLoc().getSourceRange().getBegin(), |
| TypeArgsLAngleLoc, ActualTypeArgInfos, TypeArgsRAngleLoc, |
| ProtocolLAngleLoc, |
| llvm::makeArrayRef((ObjCProtocolDecl * const *)Protocols.data(), |
| Protocols.size()), |
| ProtocolLocs, ProtocolRAngleLoc, |
| /*FailOnError=*/false); |
| |
| if (Result == T) |
| return BaseType; |
| |
| // Create source information for this type. |
| TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result); |
| TypeLoc ResultTL = ResultTInfo->getTypeLoc(); |
| |
| // For id<Proto1, Proto2> or Class<Proto1, Proto2>, we'll have an |
| // object pointer type. Fill in source information for it. |
| if (auto ObjCObjectPointerTL = ResultTL.getAs<ObjCObjectPointerTypeLoc>()) { |
| // The '*' is implicit. |
| ObjCObjectPointerTL.setStarLoc(SourceLocation()); |
| 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. |
| if (ObjCObjectTL.getNumTypeArgs() > 0) { |
| assert(ObjCObjectTL.getNumTypeArgs() == ActualTypeArgInfos.size()); |
| ObjCObjectTL.setTypeArgsLAngleLoc(TypeArgsLAngleLoc); |
| ObjCObjectTL.setTypeArgsRAngleLoc(TypeArgsRAngleLoc); |
| for (unsigned i = 0, n = ActualTypeArgInfos.size(); i != n; ++i) |
| ObjCObjectTL.setTypeArgTInfo(i, ActualTypeArgInfos[i]); |
| } else { |
| ObjCObjectTL.setTypeArgsLAngleLoc(SourceLocation()); |
| ObjCObjectTL.setTypeArgsRAngleLoc(SourceLocation()); |
| } |
| |
| // Protocol qualifier information. |
| if (ObjCObjectTL.getNumProtocols() > 0) { |
| assert(ObjCObjectTL.getNumProtocols() == Protocols.size()); |
| ObjCObjectTL.setProtocolLAngleLoc(ProtocolLAngleLoc); |
| ObjCObjectTL.setProtocolRAngleLoc(ProtocolRAngleLoc); |
| for (unsigned i = 0, n = Protocols.size(); i != n; ++i) |
| ObjCObjectTL.setProtocolLoc(i, ProtocolLocs[i]); |
| } else { |
| ObjCObjectTL.setProtocolLAngleLoc(SourceLocation()); |
| ObjCObjectTL.setProtocolRAngleLoc(SourceLocation()); |
| } |
| |
| // Base type. |
| ObjCObjectTL.setHasBaseTypeAsWritten(true); |
| if (ObjCObjectTL.getType() == T) |
| ObjCObjectTL.getBaseLoc().initializeFullCopy(BaseTypeInfo->getTypeLoc()); |
| else |
| ObjCObjectTL.getBaseLoc().initialize(Context, Loc); |
| |
| // We're done. Return the completed type to the parser. |
| return CreateParsedType(Result, ResultTInfo); |
| } |
| |
| static OpenCLAccessAttr::Spelling |
| getImageAccess(const ParsedAttributesView &Attrs) { |
| for (const ParsedAttr &AL : Attrs) |
| if (AL.getKind() == ParsedAttr::AT_OpenCLAccess) |
| return static_cast<OpenCLAccessAttr::Spelling>(AL.getSemanticSpelling()); |
| return OpenCLAccessAttr::Keyword_read_only; |
| } |
| |
| /// Convert the specified declspec to the appropriate type |
| /// object. |
| /// \param state Specifies the declarator containing the declaration specifier |
| /// to be converted, along with other associated processing state. |
| /// \returns The type described by the declaration specifiers. This function |
| /// never returns null. |
| static QualType ConvertDeclSpecToType(TypeProcessingState &state) { |
| // FIXME: Should move the logic from DeclSpec::Finish to here for validity |
| // checking. |
| |
| Sema &S = state.getSema(); |
| Declarator &declarator = state.getDeclarator(); |
| DeclSpec &DS = declarator.getMutableDeclSpec(); |
| SourceLocation DeclLoc = declarator.getIdentifierLoc(); |
| if (DeclLoc.isInvalid()) |
| DeclLoc = DS.getBeginLoc(); |
| |
| ASTContext &Context = S.Context; |
| |
| QualType Result; |
| switch (DS.getTypeSpecType()) { |
| case DeclSpec::TST_void: |
| Result = Context.VoidTy; |
| break; |
| case DeclSpec::TST_char: |
| if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified) |
| Result = Context.CharTy; |
| else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) |
| Result = Context.SignedCharTy; |
| else { |
| assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned && |
| "Unknown TSS value"); |
| Result = Context.UnsignedCharTy; |
| } |
| break; |
| case DeclSpec::TST_wchar: |
| if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified) |
| Result = Context.WCharTy; |
| else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) { |
| 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_wchar_t_sign_spec) |
| << DS.getSpecifierName(DS.getTypeSpecType(), |
| Context.getPrintingPolicy()); |
| Result = Context.getUnsignedWCharType(); |
| } |
| break; |
| case DeclSpec::TST_char8: |
| assert(DS.getTypeSpecSign() == DeclSpec::TSS_unspecified && |
| "Unknown TSS value"); |
| Result = Context.Char8Ty; |
| break; |
| case DeclSpec::TST_char16: |
| assert(DS.getTypeSpecSign() == DeclSpec::TSS_unspecified && |
| "Unknown TSS value"); |
| Result = Context.Char16Ty; |
| break; |
| case DeclSpec::TST_char32: |
| assert(DS.getTypeSpecSign() == DeclSpec::TSS_unspecified && |
| "Unknown TSS value"); |
| Result = Context.Char32Ty; |
| break; |
| case DeclSpec::TST_unspecified: |
| // If this is a missing declspec in a block literal return context, then it |
| // is inferred from the return statements inside the block. |
| // The declspec is always missing in a lambda expr context; it is either |
| // specified with a trailing return type or inferred. |
| if (S.getLangOpts().CPlusPlus14 && |
| declarator.getContext() == DeclaratorContext::LambdaExprContext) { |
| // In C++1y, a lambda's implicit return type is 'auto'. |
| Result = Context.getAutoDeductType(); |
| break; |
| } else if (declarator.getContext() == |
| DeclaratorContext::LambdaExprContext || |
| checkOmittedBlockReturnType(S, declarator, |
| Context.DependentTy)) { |
| Result = Context.DependentTy; |
| break; |
| } |
| |
| // Unspecified typespec defaults to int in C90. However, the C90 grammar |
| // [C90 6.5] only allows a decl-spec if there was *some* type-specifier, |
| // type-qualifier, or storage-class-specifier. If not, emit an extwarn. |
| // Note that the one exception to this is function definitions, which are |
| // allowed to be completely missing a declspec. This is handled in the |
| // parser already though by it pretending to have seen an 'int' in this |
| // case. |
| if (S.getLangOpts().ImplicitInt) { |
| // In C89 mode, we only warn if there is a completely missing declspec |
| // when one is not allowed. |
| if (DS.isEmpty()) { |
| S.Diag(DeclLoc, diag::ext_missing_declspec) |
| << DS.getSourceRange() |
| << FixItHint::CreateInsertion(DS.getBeginLoc(), "int"); |
| } |
| } else if (!DS.hasTypeSpecifier()) { |
| // C99 and C++ require a type specifier. For example, C99 6.7.2p2 says: |
| // "At least one type specifier shall be given in the declaration |
| // specifiers in each declaration, and in the specifier-qualifier list in |
| // each struct declaration and type name." |
| if (S.getLangOpts().CPlusPlus && !DS.isTypeSpecPipe()) { |
| S.Diag(DeclLoc, diag::err_missing_type_specifier) |
| << DS.getSourceRange(); |
| |
| // When this occurs in C++ code, often something is very broken with the |
| // value being declared, poison it as invalid so we don't get chains of |
| // errors. |
| declarator.setInvalidType(true); |
| } else if ((S.getLangOpts().OpenCLVersion >= 200 || |
| S.getLangOpts().OpenCLCPlusPlus) && |
| DS.isTypeSpecPipe()) { |
| S.Diag(DeclLoc, diag::err_missing_actual_pipe_type) |
| << DS.getSourceRange(); |
| declarator.setInvalidType(true); |
| } else { |
| S.Diag(DeclLoc, diag::ext_missing_type_specifier) |
| << DS.getSourceRange(); |
| } |
| } |
| |
| LLVM_FALLTHROUGH; |
| case DeclSpec::TST_int: { |
| if (DS.getTypeSpecSign() != DeclSpec::TSS_unsigned) { |
| switch (DS.getTypeSpecWidth()) { |
| case DeclSpec::TSW_unspecified: Result = Context.IntTy; break; |
| case DeclSpec::TSW_short: Result = Context.ShortTy; break; |
| case DeclSpec::TSW_long: Result = Context.LongTy; break; |
| case DeclSpec::TSW_longlong: |
| Result = Context.LongLongTy; |
| |
| // 'long long' is a C99 or C++11 feature. |
| if (!S.getLangOpts().C99) { |
| if (S.getLangOpts().CPlusPlus) |
| S.Diag(DS.getTypeSpecWidthLoc(), |
| S.getLangOpts().CPlusPlus11 ? |
| diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong); |
| else |
| S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_c99_longlong); |
| } |
| break; |
| } |
| } else { |
| switch (DS.getTypeSpecWidth()) { |
| case DeclSpec::TSW_unspecified: Result = Context.UnsignedIntTy; break; |
| case DeclSpec::TSW_short: Result = Context.UnsignedShortTy; break; |
| case DeclSpec::TSW_long: Result = Context.UnsignedLongTy; break; |
| case DeclSpec::TSW_longlong: |
| Result = Context.UnsignedLongLongTy; |
| |
| // 'long long' is a C99 or C++11 feature. |
| if (!S.getLangOpts().C99) { |
| if (S.getLangOpts().CPlusPlus) |
| S.Diag(DS.getTypeSpecWidthLoc(), |
| S.getLangOpts().CPlusPlus11 ? |
| diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong); |
| else |
| S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_c99_longlong); |
| } |
| break; |
| } |
| } |
| break; |
| } |
| case DeclSpec::TST_accum: { |
| switch (DS.getTypeSpecWidth()) { |
| case DeclSpec::TSW_short: |
| Result = Context.ShortAccumTy; |
| break; |
| case DeclSpec::TSW_unspecified: |
| Result = Context.AccumTy; |
| break; |
| case DeclSpec::TSW_long: |
| Result = Context.LongAccumTy; |
| break; |
| case DeclSpec::TSW_longlong: |
| llvm_unreachable("Unable to specify long long as _Accum width"); |
| } |
| |
| if (DS.getTypeSpecSign() == DeclSpec::TSS_unsigned) |
| Result = Context.getCorrespondingUnsignedType(Result); |
| |
| if (DS.isTypeSpecSat()) |
| Result = Context.getCorrespondingSaturatedType(Result); |
| |
| break; |
| } |
| case DeclSpec::TST_fract: { |
| switch (DS.getTypeSpecWidth()) { |
| case DeclSpec::TSW_short: |
| Result = Context.ShortFractTy; |
| break; |
| case DeclSpec::TSW_unspecified: |
| Result = Context.FractTy; |
| break; |
| case DeclSpec::TSW_long: |
| Result = Context.LongFractTy; |
| break; |
| case DeclSpec::TSW_longlong: |
| llvm_unreachable("Unable to specify long long as _Fract width"); |
| } |
| |
| if (DS.getTypeSpecSign() == DeclSpec::TSS_unsigned) |
| Result = Context.getCorrespondingUnsignedType(Result); |
| |
| if (DS.isTypeSpecSat()) |
| Result = Context.getCorrespondingSaturatedType(Result); |
| |
| break; |
| } |
| case DeclSpec::TST_int128: |
| if (!S.Context.getTargetInfo().hasInt128Type() && |
| !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) |
| S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) |
| << "__int128"; |
| if (DS.getTypeSpecSign() == DeclSpec::TSS_unsigned) |
| Result = Context.UnsignedInt128Ty; |
| else |
| Result = Context.Int128Ty; |
| break; |
| case DeclSpec::TST_float16: |
| // CUDA host and device may have different _Float16 support, therefore |
| // do not diagnose _Float16 usage to avoid false alarm. |
| // ToDo: more precise diagnostics for CUDA. |
| if (!S.Context.getTargetInfo().hasFloat16Type() && !S.getLangOpts().CUDA && |
| !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) |
| S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) |
| << "_Float16"; |
| Result = Context.Float16Ty; |
| break; |
| case DeclSpec::TST_half: Result = Context.HalfTy; break; |
| case DeclSpec::TST_float: Result = Context.FloatTy; break; |
| case DeclSpec::TST_double: |
| if (DS.getTypeSpecWidth() == DeclSpec::TSW_long) |
| Result = Context.LongDoubleTy; |
| else |
| Result = Context.DoubleTy; |
| break; |
| case DeclSpec::TST_float128: |
| if (!S.Context.getTargetInfo().hasFloat128Type() && |
| !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) |
| S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) |
| << "__float128"; |
| Result = Context.Float128Ty; |
| break; |
| case DeclSpec::TST_bool: Result = Context.BoolTy; break; // _Bool or bool |
| break; |
| case DeclSpec::TST_decimal32: // _Decimal32 |
| case DeclSpec::TST_decimal64: // _Decimal64 |
| case DeclSpec::TST_decimal128: // _Decimal128 |
| S.Diag(DS.getTypeSpecTypeLoc(), diag::err_decimal_unsupported); |
| Result = Context.IntTy; |
| declarator.setInvalidType(true); |
| break; |
| case DeclSpec::TST_class: |
| case DeclSpec::TST_enum: |
| case DeclSpec::TST_union: |
| case DeclSpec::TST_struct: |
| case DeclSpec::TST_interface: { |
| TagDecl *D = dyn_cast_or_null<TagDecl>(DS.getRepAsDecl()); |
| if (!D) { |
| // This can happen in C++ with ambiguous lookups. |
| Result = Context.IntTy; |
| declarator.setInvalidType(true); |
| break; |
| } |
| |
| // If the type is deprecated or unavailable, diagnose it. |
| S.DiagnoseUseOfDecl(D, DS.getTypeSpecTypeNameLoc()); |
| |
| assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && |
| DS.getTypeSpecSign() == 0 && "No qualifiers on tag names!"); |
| |
| // TypeQuals handled by caller. |
| Result = Context.getTypeDeclType(D); |
| |
| // In both C and C++, make an ElaboratedType. |
| ElaboratedTypeKeyword Keyword |
| = ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType()); |
| Result = S.getElaboratedType(Keyword, DS.getTypeSpecScope(), Result, |
| DS.isTypeSpecOwned() ? D : nullptr); |
| break; |
| } |
| case DeclSpec::TST_typename: { |
| assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && |
| DS.getTypeSpecSign() == 0 && |
| "Can't handle qualifiers on typedef names yet!"); |
| Result = S.GetTypeFromParser(DS.getRepAsType()); |
| if (Result.isNull()) { |
| declarator.setInvalidType(true); |
| } |
| |
| // TypeQuals handled by caller. |
| break; |
| } |
| case DeclSpec::TST_typeofType: |
| // FIXME: Preserve type source info. |
| Result = S.GetTypeFromParser(DS.getRepAsType()); |
| assert(!Result.isNull() && "Didn't get a type for typeof?"); |
| if (!Result->isDependentType()) |
| if (const TagType *TT = Result->getAs<TagType>()) |
| S.DiagnoseUseOfDecl(TT->getDecl(), DS.getTypeSpecTypeLoc()); |
| // TypeQuals handled by caller. |
| Result = Context.getTypeOfType(Result); |
| break; |
| case DeclSpec::TST_typeofExpr: { |
| Expr *E = DS.getRepAsExpr(); |
| assert(E && "Didn't get an expression for typeof?"); |
| // TypeQuals handled by caller. |
| Result = S.BuildTypeofExprType(E, DS.getTypeSpecTypeLoc()); |
| if (Result.isNull()) { |
| Result = Context.IntTy; |
| declarator.setInvalidType(true); |
| } |
| break; |
| } |
| case DeclSpec::TST_decltype: { |
| Expr *E = DS.getRepAsExpr(); |
| assert(E && "Didn't get an expression for decltype?"); |
| // TypeQuals handled by caller. |
| Result = S.BuildDecltypeType(E, DS.getTypeSpecTypeLoc()); |
| if (Result.isNull()) { |
| Result = Context.IntTy; |
| declarator.setInvalidType(true); |
| } |
| break; |
| } |
| case DeclSpec::TST_underlyingType: |
| Result = S.GetTypeFromParser(DS.getRepAsType()); |
| assert(!Result.isNull() && "Didn't get a type for __underlying_type?"); |
| Result = S.BuildUnaryTransformType(Result, |
| UnaryTransformType::EnumUnderlyingType, |
| DS.getTypeSpecTypeLoc()); |
| if (Result.isNull()) { |
| Result = Context.IntTy; |
| declarator.setInvalidType(true); |
| } |
| break; |
| |
| case DeclSpec::TST_auto: |
| Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false); |
| break; |
| |
| case DeclSpec::TST_auto_type: |
| Result = Context.getAutoType(QualType(), AutoTypeKeyword::GNUAutoType, false); |
| break; |
| |
| case DeclSpec::TST_decltype_auto: |
| Result = Context.getAutoType(QualType(), AutoTypeKeyword::DecltypeAuto, |
| /*IsDependent*/ false); |
| break; |
| |
| case DeclSpec::TST_unknown_anytype: |
| Result = Context.UnknownAnyTy; |
| break; |
| |
| case DeclSpec::TST_atomic: |
| Result = S.GetTypeFromParser(DS.getRepAsType()); |
| assert(!Result.isNull() && "Didn't get a type for _Atomic?"); |
| Result = S.BuildAtomicType(Result, DS.getTypeSpecTypeLoc()); |
| if (Result.isNull()) { |
| Result = Context.IntTy; |
| declarator.setInvalidType(true); |
| } |
| break; |
| |
| #define GENERIC_IMAGE_TYPE(ImgType, Id) \ |
| case DeclSpec::TST_##ImgType##_t: \ |
| switch (getImageAccess(DS.getAttributes())) { \ |
| 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; \ |
| case OpenCLAccessAttr::SpellingNotCalculated: \ |
| llvm_unreachable("Spelling not yet calculated"); \ |
| } \ |
| break; |
| #include "clang/Basic/OpenCLImageTypes.def" |
| |
| case DeclSpec::TST_error: |
| Result = Context.IntTy; |
| declarator.setInvalidType(true); |
| break; |
| } |
| |
| if (S.getLangOpts().OpenCL && |
| S.checkOpenCLDisabledTypeDeclSpec(DS, Result)) |
| declarator.setInvalidType(true); |
| |
| bool IsFixedPointType = DS.getTypeSpecType() == DeclSpec::TST_accum || |
| DS.getTypeSpecType() == DeclSpec::TST_fract; |
| |
| // Only fixed point types can be saturated |
| if (DS.isTypeSpecSat() && !IsFixedPointType) |
| S.Diag(DS.getTypeSpecSatLoc(), diag::err_invalid_saturation_spec) |
| << DS.getSpecifierName(DS.getTypeSpecType(), |
| Context.getPrintingPolicy()); |
| |
| // Handle complex types. |
| if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) { |
| if (S.getLangOpts().Freestanding) |
| S.Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex); |
| Result = Context.getComplexType(Result); |
| } else if (DS.isTypeAltiVecVector()) { |
| unsigned typeSize = static_cast<unsigned>(Context.getTypeSize(Result)); |
| assert(typeSize > 0 && "type size for vector must be greater than 0 bits"); |
| VectorType::VectorKind VecKind = VectorType::AltiVecVector; |
| if (DS.isTypeAltiVecPixel()) |
| VecKind = VectorType::AltiVecPixel; |
| else if (DS.isTypeAltiVecBool()) |
| VecKind = VectorType::AltiVecBool; |
| Result = Context.getVectorType(Result, 128/typeSize, VecKind); |
| } |
| |
| // FIXME: Imaginary. |
| if (DS.getTypeSpecComplex() == DeclSpec::TSC_imaginary) |
| S.Diag(DS.getTypeSpecComplexLoc(), diag::err_imaginary_not_supported); |
| |
| // Before we process any type attributes, synthesize a block literal |
| // function declarator if necessary. |
| if (declarator.getContext() == DeclaratorContext::BlockLiteralContext) |
| maybeSynthesizeBlockSignature(state, Result); |
| |
| // Apply any type attributes from the decl spec. This may cause the |
| // list of type attributes to be temporarily saved while the type |
| // attributes are pushed around. |
| // pipe attributes will be handled later ( at GetFullTypeForDeclarator ) |
| if (!DS.isTypeSpecPipe()) |
| processTypeAttrs(state, Result, TAL_DeclSpec, DS.getAttributes()); |
| |
| // Apply const/volatile/restrict qualifiers to T. |
| if (unsigned TypeQuals = DS.getTypeQualifiers()) { |
| // Warn about CV qualifiers on function types. |
| // C99 6.7.3p8: |
| // If the specification of a function type includes any type qualifiers, |
| // the behavior is undefined. |
| // C++11 [dcl.fct]p7: |
| // The effect of a cv-qualifier-seq in a function declarator is not the |
| // same as adding cv-qualification on top of the function type. In the |
| // latter case, the cv-qualifiers are ignored. |
| if (TypeQuals && Result->isFunctionType()) { |
| diagnoseAndRemoveTypeQualifiers( |
| S, DS, TypeQuals, Result, DeclSpec::TQ_const | DeclSpec::TQ_volatile, |
| S.getLangOpts().CPlusPlus |
| ? diag::warn_typecheck_function_qualifiers_ignored |
| : diag::warn_typecheck_function_qualifiers_unspecified); |
| // No diagnostic for 'restrict' or '_Atomic' applied to a |
| // function type; we'll diagnose those later, in BuildQualifiedType. |
| } |
| |
| // C++11 [dcl.ref]p1: |
| // Cv-qualified references are ill-formed except when the |
| // cv-qualifiers are introduced through the use of a typedef-name |
| // or decltype-specifier, in which case the cv-qualifiers are ignored. |
| // |
| // There don't appear to be any other contexts in which a cv-qualified |
| // reference type could be formed, so the 'ill-formed' clause here appears |
| // to never happen. |
| if (TypeQuals && Result->isReferenceType()) { |
| diagnoseAndRemoveTypeQualifiers( |
| S, DS, TypeQuals, Result, |
| DeclSpec::TQ_const | DeclSpec::TQ_volatile | DeclSpec::TQ_atomic, |
| diag::warn_typecheck_reference_qualifiers); |
| } |
| |
| // C90 6.5.3 constraints: "The same type qualifier shall not appear more |
| // than once in the same specifier-list or qualifier-list, either directly |
| // or via one or more typedefs." |
| if (!S.getLangOpts().C99 && !S.getLangOpts().CPlusPlus |
| && TypeQuals & Result.getCVRQualifiers()) { |
| if (TypeQuals & DeclSpec::TQ_const && Result.isConstQualified()) { |
| S.Diag(DS.getConstSpecLoc(), diag::ext_duplicate_declspec) |
| << "const"; |
| } |
| |
| if (TypeQuals & DeclSpec::TQ_volatile && Result.isVolatileQualified()) { |
| S.Diag(DS.getVolatileSpecLoc(), diag::ext_duplicate_declspec) |
| << "volatile"; |
| } |
| |
| // C90 doesn't have restrict nor _Atomic, so it doesn't force us to |
| // produce a warning in this case. |
| } |
| |
| QualType Qualified = S.BuildQualifiedType(Result, DeclLoc, TypeQuals, &DS); |
| |
| // If adding qualifiers fails, just use the unqualified type. |
| if (Qualified.isNull()) |
| declarator.setInvalidType(true); |
| else |
| Result = Qualified; |
| } |
| |
| assert(!Result.isNull() && "This function should not return a null type"); |
| return Result; |
| } |
| |
| static std::string getPrintableNameForEntity(DeclarationName Entity) { |
| if (Entity) |
| return Entity.getAsString(); |
| |
| return "type name"; |
| } |
| |
| QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, |
| Qualifiers Qs, const DeclSpec *DS) { |
| 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()) { |
| unsigned DiagID = 0; |
| QualType ProblemTy; |
| |
| if (T->isAnyPointerType() || T->isReferenceType() || |
| T->isMemberPointerType()) { |
| QualType EltTy; |
| if (T->isObjCObjectPointerType()) |
| EltTy = T; |
| else if (const MemberPointerType *PTy = T->getAs<MemberPointerType>()) |
| EltTy = PTy->getPointeeType(); |
| else |
| EltTy = T->getPointeeType(); |
| |
| // If we have a pointer or reference, the pointee must have an object |
| // incomplete type. |
| if (!EltTy->isIncompleteOrObjectType()) { |
| DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee; |
| ProblemTy = EltTy; |
| } |
| } else if (!T->isDependentType()) { |
| DiagID = diag::err_typecheck_invalid_restrict_not_pointer; |
| ProblemTy = T; |
| } |
| |
| if (DiagID) { |
| Diag(DS ? DS->getRestrictSpecLoc() : Loc, DiagID) << ProblemTy; |
| Qs.removeRestrict(); |
| } |
| } |
| |
| return Context.getQualifiedType(T, Qs); |
| } |
| |
| QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, |
| unsigned CVRAU, const DeclSpec *DS) { |
| 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); |
| |
| // C11 6.7.3/5: |
| // If the same qualifier appears more than once in the same |
| // specifier-qualifier-list, either directly or via one or more typedefs, |
| // the behavior is the same as if it appeared only once. |
| // |
| // It's not specified what happens when the _Atomic qualifier is applied to |
| // a type specified with the _Atomic specifier, but we assume that this |
| // should be treated as if the _Atomic qualifier appeared multiple times. |
| if (CVRAU & DeclSpec::TQ_atomic && !T->isAtomicType()) { |
| // C11 6.7.3/5: |
| // If other qualifiers appear along with the _Atomic qualifier in a |
| // specifier-qualifier-list, the resulting type is the so-qualified |
| // atomic type. |
| // |
| // Don't need to worry about array types here, since _Atomic can't be |
| // applied to such types. |
| SplitQualType Split = T.getSplitUnqualifiedType(); |
| T = BuildAtomicType(QualType(Split.Ty, 0), |
| DS ? DS->getAtomicSpecLoc() : Loc); |
| if (T.isNull()) |
| return T; |
| Split.Quals.addCVRQualifiers(CVR); |
| return BuildQualifiedType(T, Loc, Split.Quals); |
| } |
| |
| Qualifiers Q = Qualifiers::fromCVRMask(CVR); |
| Q.setUnaligned(CVRAU & DeclSpec::TQ_unaligned); |
| return BuildQualifiedType(T, Loc, Q, DS); |
| } |
| |
| /// Build a paren type including \p T. |
| QualType Sema::BuildParenType(QualType T) { |
| return Context.getParenType(T); |
| } |
| |
| /// Given that we're building a pointer or reference to the given |
| static QualType inferARCLifetimeForPointee(Sema &S, QualType type, |
| SourceLocation loc, |
| bool isReference) { |
| // Bail out if retention is unrequired or already specified. |
| if (!type->isObjCLifetimeType() || |
| type.getObjCLifetime() != Qualifiers::OCL_None) |
| return type; |
| |
| Qualifiers::ObjCLifetime implicitLifetime = Qualifiers::OCL_None; |
| |
| // If the object type is const-qualified, we can safely use |
| // __unsafe_unretained. This is safe (because there are no read |
| // barriers), and it'll be safe to coerce anything but __weak* to |
| // the resulting type. |
| if (type.isConstQualified()) { |
| implicitLifetime = Qualifiers::OCL_ExplicitNone; |
| |
| // Otherwise, check whether the static type does not require |
| // retaining. This currently only triggers for Class (possibly |
| // protocol-qualifed, and arrays thereof). |
| } else if (type->isObjCARCImplicitlyUnretainedType()) { |
| implicitLifetime = Qualifiers::OCL_ExplicitNone; |
| |
| // If we are in an unevaluated context, like sizeof, skip adding a |
| // qualification. |
| } else if (S.isUnevaluatedContext()) { |
| return type; |
| |
| // If that failed, give an error and recover using __strong. __strong |
| // is the option most likely to prevent spurious second-order diagnostics, |
| // like when binding a reference to a field. |
| } else { |
| // These types can show up in private ivars in system headers, so |
| // we need this to not be an error in those cases. Instead we |
| // want to delay. |
| if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { |
| S.DelayedDiagnostics.add( |
| sema::DelayedDiagnostic::makeForbiddenType(loc, |
| diag::err_arc_indirect_no_ownership, type, isReference)); |
| } else { |
| S.Diag(loc, diag::err_arc_indirect_no_ownership) << type << isReference; |
| } |
| implicitLifetime = Qualifiers::OCL_Strong; |
| } |
| assert(implicitLifetime && "didn't infer any lifetime!"); |
| |
| Qualifiers qs; |
| qs.addObjCLifetime(implicitLifetime); |
| return S.Context.getQualifiedType(type, qs); |
| } |
| |
| static std::string getFunctionQualifiersAsString(const FunctionProtoType *FnTy){ |
| std::string Quals = FnTy->getMethodQuals().getAsString(); |
| |
| switch (FnTy->getRefQualifier()) { |
| case RQ_None: |
| break; |
| |
| case RQ_LValue: |
| if (!Quals.empty()) |
| Quals += ' '; |
| Quals += '&'; |
| break; |
| |
| case RQ_RValue: |
| if (!Quals.empty()) |
| Quals += ' '; |
| Quals += "&&"; |
| break; |
| } |
| |
| return Quals; |
| } |
| |
| namespace { |
| /// Kinds of declarator that cannot contain a qualified function type. |
| /// |
| /// C++98 [dcl.fct]p4 / C++11 [dcl.fct]p6: |
| /// a function type with a cv-qualifier or a ref-qualifier can only appear |
| /// at the topmost level of a type. |
| /// |
| /// Parens and member pointers are permitted. We don't diagnose array and |
| /// function declarators, because they don't allow function types at all. |
| /// |
| /// The values of this enum are used in diagnostics. |
| enum QualifiedFunctionKind { QFK_BlockPointer, QFK_Pointer, QFK_Reference }; |
| } // end anonymous namespace |
| |
| /// Check whether the type T is a qualified function type, and if it is, |
| /// diagnose that it cannot be contained within the given kind of declarator. |
| 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)) |
| return false; |
| |
| S.Diag(Loc, diag::err_compound_qualified_function_type) |
| << QFK << isa<FunctionType>(T.IgnoreParens()) << T |
| << getFunctionQualifiersAsString(FPT); |
| 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. |
| /// |
| /// \param Loc The location of the entity whose type involves this |
| /// pointer type or, if there is no such entity, the location of the |
| /// type that will have pointer type. |
| /// |
| /// \param Entity The name of the entity that involves the pointer |
| /// type, if known. |
| /// |
| /// \returns A suitable pointer type, if there are no |
| /// errors. Otherwise, returns a NULL type. |
| QualType Sema::BuildPointerType(QualType T, |
| SourceLocation Loc, DeclarationName Entity) { |
| if (T->isReferenceType()) { |
| // C++ 8.3.2p4: There shall be no ... pointers to references ... |
| Diag(Loc, diag::err_illegal_decl_pointer_to_reference) |
| << getPrintableNameForEntity(Entity) << T; |
| return QualType(); |
| } |
| |
| if (T->isFunctionType() && getLangOpts().OpenCL) { |
| Diag(Loc, diag::err_opencl_function_pointer); |
| return QualType(); |
| } |
| |
| if (checkQualifiedFunction(*this, T, Loc, QFK_Pointer)) |
| return QualType(); |
| |
| assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType"); |
| |
| // In ARC, it is forbidden to build pointers to unqualified pointers. |
| if (getLangOpts().ObjCAutoRefCount) |
| T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ false); |
| |
| // Build the pointer type. |
| return Context.getPointerType(T); |
| } |
| |
| /// Build a reference type. |
| /// |
| /// \param T The type to which we'll be building a reference. |
| /// |
| /// \param Loc The location of the entity whose type involves this |
| /// reference type or, if there is no such entity, the location of the |
| /// type that will have reference type. |
| /// |
| /// \param Entity The name of the entity that involves the reference |
| /// type, if known. |
| /// |
| /// \returns A suitable reference type, if there are no |
| /// errors. Otherwise, returns a NULL type. |
| QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, |
| SourceLocation Loc, |
| DeclarationName Entity) { |
| assert(Context.getCanonicalType(T) != Context.OverloadTy && |
| "Unresolved overloaded function type"); |
| |
| // C++0x [dcl.ref]p6: |
| // If a typedef (7.1.3), a type template-parameter (14.3.1), or a |
| // decltype-specifier (7.1.6.2) denotes a type TR that is a reference to a |
| // type T, an attempt to create the type "lvalue reference to cv TR" creates |
| // the type "lvalue reference to T", while an attempt to create the type |
| // "rvalue reference to cv TR" creates the type TR. |
| bool LValueRef = SpelledAsLValue || T->getAs<LValueReferenceType>(); |
| |
| // C++ [dcl.ref]p4: There shall be no references to references. |
| // |
| // According to C++ DR 106, references to references are only |
| // diagnosed when they are written directly (e.g., "int & &"), |
| // but not when they happen via a typedef: |
| // |
| // typedef int& intref; |
| // typedef intref& intref2; |
| // |
| // Parser::ParseDeclaratorInternal diagnoses the case where |
| // references are written directly; here, we handle the |
| // collapsing of references-to-references as described in C++0x. |
| // DR 106 and 540 introduce reference-collapsing into C++98/03. |
| |
| // C++ [dcl.ref]p1: |
| // A declarator that specifies the type "reference to cv void" |
| // is ill-formed. |
| if (T->isVoidType()) { |
| Diag(Loc, diag::err_reference_to_void); |
| return QualType(); |
| } |
| |
| if (checkQualifiedFunction(*this, T, Loc, QFK_Reference)) |
| return QualType(); |
| |
| // In ARC, it is forbidden to build references to unqualified pointers. |
| if (getLangOpts().ObjCAutoRefCount) |
| T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ true); |
| |
| // Handle restrict on references. |
| if (LValueRef) |
| return Context.getLValueReferenceType(T, SpelledAsLValue); |
| return Context.getRValueReferenceType(T); |
| } |
| |
| /// Build a Read-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::BuildReadPipeType(QualType T, SourceLocation Loc) { |
| return Context.getReadPipeType(T); |
| } |
| |
| /// 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, |
| /// return true, if not, return the size of the array in SizeVal. |
| static bool isArraySizeVLA(Sema &S, Expr *ArraySize, llvm::APSInt &SizeVal) { |
| // If the size is an ICE, it certainly isn't a VLA. If we're in a GNU mode |
| // (like gnu99, but not c99) accept any evaluatable value as an extension. |
| class VLADiagnoser : public Sema::VerifyICEDiagnoser { |
| public: |
| VLADiagnoser() : Sema::VerifyICEDiagnoser(true) {} |
| |
| void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) override { |
| } |
| |
| void diagnoseFold(Sema &S, SourceLocation Loc, SourceRange SR) override { |
| S.Diag(Loc, diag::ext_vla_folded_to_constant) << SR; |
| } |
| } Diagnoser; |
| |
| return S.VerifyIntegerConstantExpression(ArraySize, &SizeVal, Diagnoser, |
| S.LangOpts.GNUMode || |
| S.LangOpts.OpenCL).isInvalid(); |
| } |
| |
| /// Build an array type. |
| /// |
| /// \param T The type of each element in the array. |
| /// |
| /// \param ASM C99 array size modifier (e.g., '*', 'static'). |
| /// |
| /// \param ArraySize Expression describing the size of the array. |
| /// |
| /// \param Brackets The range from the opening '[' to the closing ']'. |
| /// |
| /// \param Entity The name of the entity that involves the array |
| /// type, if known. |
| /// |
| /// \returns A suitable array type, if there are no errors. Otherwise, |
| /// returns a NULL type. |
| QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, |
| Expr *ArraySize, unsigned Quals, |
| SourceRange Brackets, DeclarationName Entity) { |
| |
| SourceLocation Loc = Brackets.getBegin(); |
| if (getLangOpts().CPlusPlus) { |
| // C++ [dcl.array]p1: |
| // T is called the array element type; this type shall not be a reference |
| // type, the (possibly cv-qualified) type void, a function type or an |
| // abstract class type. |
| // |
| // C++ [dcl.array]p3: |
| // When several "array of" specifications are adjacent, [...] only the |
| // first of the constant expressions that specify the bounds of the arrays |
| // may be omitted. |
| // |
| // Note: function types are handled in the common path with C. |
| if (T->isReferenceType()) { |
| Diag(Loc, diag::err_illegal_decl_array_of_references) |
| << getPrintableNameForEntity(Entity) << T; |
| return QualType(); |
| } |
| |
| if (T->isVoidType() || T->isIncompleteArrayType()) { |
| Diag(Loc, diag::err_illegal_decl_array_incomplete_type) << T; |
| return QualType(); |
| } |
| |
| if (RequireNonAbstractType(Brackets.getBegin(), T, |
| diag::err_array_of_abstract_type)) |
| return QualType(); |
| |
| // Mentioning a member pointer type for an array type causes us to lock in |
| // an inheritance model, even if it's inside an unused typedef. |
| if (Context.getTargetInfo().getCXXABI().isMicrosoft()) |
| if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>()) |
| if (!MPTy->getClass()->isDependentType()) |
| (void)isCompleteType(Loc, T); |
| |
| } else { |
| // C99 6.7.5.2p1: If the element type is an incomplete or function type, |
| // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]()) |
| if (RequireCompleteType(Loc, T, |
| diag::err_illegal_decl_array_incomplete_type)) |
| return QualType(); |
| } |
| |
| if (T->isFunctionType()) { |
| Diag(Loc, diag::err_illegal_decl_array_of_functions) |
| << getPrintableNameForEntity(Entity) << T; |
| return QualType(); |
| } |
| |
| if (const RecordType *EltTy = T->getAs<RecordType>()) { |
| // If the element type is a struct or union that contains a variadic |
| // array, accept it as a GNU extension: C99 6.7.2.1p2. |
| if (EltTy->getDecl()->hasFlexibleArrayMember()) |
| Diag(Loc, diag::ext_flexible_array_in_array) << T; |
| } else if (T->isObjCObjectType()) { |
| Diag(Loc, diag::err_objc_array_of_interfaces) << T; |
| return QualType(); |
| } |
| |
| // Do placeholder conversions on the array size expression. |
| if (ArraySize && ArraySize->hasPlaceholderType()) { |
| ExprResult Result = CheckPlaceholderExpr(ArraySize); |
| if (Result.isInvalid()) return QualType(); |
| ArraySize = Result.get(); |
| } |
| |
| // Do lvalue-to-rvalue conversions on the array size expression. |
| if (ArraySize && !ArraySize->isRValue()) { |
| ExprResult Result = DefaultLvalueConversion(ArraySize); |
| if (Result.isInvalid()) |
| return QualType(); |
| |
| ArraySize = Result.get(); |
| } |
| |
| // C99 6.7.5.2p1: The size expression shall have integer type. |
| // C++11 allows contextual conversions to such types. |
| if (!getLangOpts().CPlusPlus11 && |
| ArraySize && !ArraySize->isTypeDependent() && |
| !ArraySize->getType()->isIntegralOrUnscopedEnumerationType()) { |
| Diag(ArraySize->getBeginLoc(), diag::err_array_size_non_int) |
| << ArraySize->getType() << ArraySize->getSourceRange(); |
| return QualType(); |
| } |
| |
| llvm::APSInt ConstVal(Context.getTypeSize(Context.getSizeType())); |
| if (!ArraySize) { |
| if (ASM == ArrayType::Star) |
| T = Context.getVariableArrayType(T, nullptr, ASM, Quals, Brackets); |
| else |
| T = Context.getIncompleteArrayType(T, ASM, Quals); |
| } else if (ArraySize->isTypeDependent() || ArraySize->isValueDependent()) { |
| T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets); |
| } else if ((!T->isDependentType() && !T->isIncompleteType() && |
| !T->isConstantSizeType()) || |
| isArraySizeVLA(*this, ArraySize, ConstVal)) { |
| // Even in C++11, don't allow contextual conversions in the array bound |
| // of a VLA. |
| if (getLangOpts().CPlusPlus11 && |
| !ArraySize->getType()->isIntegralOrUnscopedEnumerationType()) { |
| Diag(ArraySize->getBeginLoc(), diag::err_array_size_non_int) |
| << ArraySize->getType() << ArraySize->getSourceRange(); |
| return QualType(); |
| } |
| |
| // C99: an array with an element type that has a non-constant-size is a VLA. |
| // C99: an array with a non-ICE size is a VLA. We accept any expression |
| // that we can fold to a non-zero positive value as an extension. |
| T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets); |
| } else { |
| // C99 6.7.5.2p1: If the expression is a constant expression, it shall |
| // have a value greater than zero. |
| if (ConstVal.isSigned() && ConstVal.isNegative()) { |
| if (Entity) |
| Diag(ArraySize->getBeginLoc(), diag::err_decl_negative_array_size) |
| << getPrintableNameForEntity(Entity) << ArraySize->getSourceRange(); |
| else |
| Diag(ArraySize->getBeginLoc(), diag::err_typecheck_negative_array_size) |
| << ArraySize->getSourceRange(); |
| return QualType(); |
| } |
| if (ConstVal == 0) { |
| // GCC accepts zero sized static arrays. We allow them when |
| // we're not in a SFINAE context. |
| Diag(ArraySize->getBeginLoc(), isSFINAEContext() |
| ? diag::err_typecheck_zero_array_size |
| : diag::ext_typecheck_zero_array_size) |
| << ArraySize->getSourceRange(); |
| |
| if (ASM == ArrayType::Static) { |
| Diag(ArraySize->getBeginLoc(), |
| diag::warn_typecheck_zero_static_array_size) |
| << ArraySize->getSourceRange(); |
| ASM = ArrayType::Normal; |
| } |
| } else if (!T->isDependentType() && !T->isVariablyModifiedType() && |
| !T->isIncompleteType() && !T->isUndeducedType()) { |
| // Is the array too large? |
| unsigned ActiveSizeBits |
| = ConstantArrayType::getNumAddressingBits(Context, T, ConstVal); |
| if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) { |
| Diag(ArraySize->getBeginLoc(), diag::err_array_too_large) |
| << ConstVal.toString(10) << ArraySize->getSourceRange(); |
| return QualType(); |
| } |
| } |
| |
| T = Context.getConstantArrayType(T, ConstVal, ArraySize, ASM, Quals); |
| } |
| |
| // OpenCL v1.2 s6.9.d: variable length arrays are not supported. |
| if (getLangOpts().OpenCL && T->isVariableArrayType()) { |
| Diag(Loc, diag::err_opencl_vla); |
| return QualType(); |
| } |
| |
| if (T->isVariableArrayType() && !Context.getTargetInfo().isVLASupported()) { |
| // CUDA device code and some other targets don't support VLAs. |
| targetDiag(Loc, (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) |
| ? diag::err_cuda_vla |
| : diag::err_vla_unsupported) |
| << ((getLangOpts().CUDA && getLangOpts().CUDAIsDevice) |
| ? CurrentCUDATarget() |
| : CFT_InvalidTarget); |
| } |
| |
| // If this is not C99, extwarn about VLA's and C99 array size modifiers. |
| if (!getLangOpts().C99) { |
| if (T->isVariableArrayType()) { |
| // Prohibit the use of VLAs during template argument deduction. |
| if (isSFINAEContext()) { |
| Diag(Loc, diag::err_vla_in_sfinae); |
| return QualType(); |
| } |
| // Just extwarn about VLAs. |
| else |
| Diag(Loc, diag::ext_vla); |
| } else if (ASM != ArrayType::Normal || Quals != 0) |
| Diag(Loc, |
| getLangOpts().CPlusPlus? diag::err_c99_array_usage_cxx |
| : diag::ext_c99_array_usage) << ASM; |
| } |
| |
| if (T->isVariableArrayType()) { |
| // Warn about VLAs for -Wvla. |
| Diag(Loc, diag::warn_vla_used); |
| } |
| |
| // OpenCL v2.0 s6.12.5 - Arrays of blocks are not supported. |
| // OpenCL v2.0 s6.16.13.1 - Arrays of pipe type are not supported. |
| // OpenCL v2.0 s6.9.b - Arrays of image/sampler type are not supported. |
| if (getLangOpts().OpenCL) { |
| const QualType ArrType = Context.getBaseElementType(T); |
| if (ArrType->isBlockPointerType() || ArrType->isPipeType() || |
| ArrType->isSamplerT() || ArrType->isImageType()) { |
| Diag(Loc, diag::err_opencl_invalid_type_array) << ArrType; |
| return QualType(); |
| } |
| } |
| |
| return T; |
| } |
| |
| QualType Sema::BuildVectorType(QualType CurType, Expr *SizeExpr, |
| SourceLocation AttrLoc) { |
| // The base type must be integer (not Boolean or enumeration) or float, and |
| // can't already be a vector. |
| if (!CurType->isDependentType() && |
| (!CurType->isBuiltinType() || CurType->isBooleanType() || |
| (!CurType->isIntegerType() && !CurType->isRealFloatingType()))) { |
| Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << CurType; |
| return QualType(); |
| } |
| |
| if (SizeExpr->isTypeDependent() || SizeExpr->isValueDependent()) |
| return Context.getDependentVectorType(CurType, SizeExpr, AttrLoc, |
| VectorType::GenericVector); |
| |
| llvm::APSInt VecSize(32); |
| if (!SizeExpr->isIntegerConstantExpr(VecSize, Context)) { |
| Diag(AttrLoc, diag::err_attribute_argument_type) |
| << "vector_size" << AANT_ArgumentIntegerConstant |
| << SizeExpr->getSourceRange(); |
| return QualType(); |
| } |
| |
| if (CurType->isDependentType()) |
| return Context.getDependentVectorType(CurType, SizeExpr, AttrLoc, |
| VectorType::GenericVector); |
| |
| unsigned VectorSize = static_cast<unsigned>(VecSize.getZExtValue() * 8); |
| unsigned TypeSize = static_cast<unsigned>(Context.getTypeSize(CurType)); |
| |
| if (VectorSize == 0) { |
| Diag(AttrLoc, diag::err_attribute_zero_size) << SizeExpr->getSourceRange(); |
| return QualType(); |
| } |
| |
| // vecSize is specified in bytes - convert to bits. |
| if (VectorSize % TypeSize) { |
| Diag(AttrLoc, diag::err_attribute_invalid_size) |
| << SizeExpr->getSourceRange(); |
| return QualType(); |
| } |
| |
| if (VectorType::isVectorSizeTooLarge(VectorSize / TypeSize)) { |
| Diag(AttrLoc, diag::err_attribute_size_too_large) |
| << SizeExpr->getSourceRange(); |
| return QualType(); |
| } |
| |
| return Context.getVectorType(CurType, VectorSize / TypeSize, |
| VectorType::GenericVector); |
| } |
| |
| /// Build an ext-vector type. |
| /// |
| /// Run the required checks for the extended vector type. |
| QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize, |
| SourceLocation AttrLoc) { |
| // Unlike gcc's vector_size attribute, we do not allow vectors to be defined |
| // in conjunction with complex types (pointers, arrays, functions, etc.). |
| // |
| // Additionally, OpenCL prohibits vectors of booleans (they're considered a |
| // reserved data type under OpenCL v2.0 s6.1.4), we don't support selects |
| // on bitvectors, and we have no well-defined ABI for bitvectors, so vectors |
| // of bool aren't allowed. |
| if ((!T->isDependentType() && !T->isIntegerType() && |
| !T->isRealFloatingType()) || |
| T->isBooleanType()) { |
| Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << T; |
| return QualType(); |
| } |
| |
| if (!ArraySize->isTypeDependent() && !ArraySize->isValueDependent()) { |
| llvm::APSInt vecSize(32); |
| if (!ArraySize->isIntegerConstantExpr(vecSize, Context)) { |
| Diag(AttrLoc, diag::err_attribute_argument_type) |
| << "ext_vector_type" << AANT_ArgumentIntegerConstant |
| << ArraySize->getSourceRange(); |
| return QualType(); |
| } |
| |
| // Unlike gcc's vector_size attribute, the size is specified as the |
| // number of elements, not the number of bytes. |
| unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue()); |
| |
| if (vectorSize == 0) { |
| Diag(AttrLoc, diag::err_attribute_zero_size) |
| << ArraySize->getSourceRange(); |
| return QualType(); |
| } |
| |
| if (VectorType::isVectorSizeTooLarge(vectorSize)) { |
| Diag(AttrLoc, diag::err_attribute_size_too_large) |
| << ArraySize->getSourceRange(); |
| return QualType(); |
| } |
| |
| return Context.getExtVectorType(T, vectorSize); |
| } |
| |
| return Context.getDependentSizedExtVectorType(T, ArraySize, AttrLoc); |
| } |
| |
| bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) { |
| if (T->isArrayType() || T->isFunctionType()) { |
| Diag(Loc, diag::err_func_returning_array_function) |
| << T->isFunctionType() << T; |
| return true; |
| } |
| |
| // Functions cannot return half FP. |
| if (T->isHalfType() && !getLangOpts().HalfArgsAndReturns) { |
| Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 1 << |
| FixItHint::CreateInsertion(Loc, "*"); |
| return true; |
| } |
| |
| // Methods cannot return interface types. All ObjC objects are |
| // passed by reference. |
| if (T->isObjCObjectType()) { |
| Diag(Loc, diag::err_object_cannot_be_passed_returned_by_value) |
| << 0 << T << FixItHint::CreateInsertion(Loc, "*"); |
| return true; |
| } |
| |
| if (T.hasNonTrivialToPrimitiveDestructCUnion() || |
| T.hasNonTrivialToPrimitiveCopyCUnion()) |
| 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; |
| } |
| |
| /// Check the extended parameter information. Most of the necessary |
| /// checking should occur when applying the parameter attribute; the |
| /// only other checks required are positional restrictions. |
| static void checkExtParameterInfos(Sema &S, ArrayRef<QualType> paramTypes, |
| const FunctionProtoType::ExtProtoInfo &EPI, |
| llvm::function_ref<SourceLocation(unsigned)> getParamLoc) { |
| assert(EPI.ExtParameterInfos && "shouldn't get here without param infos"); |
| |
| bool hasCheckedSwiftCall = false; |
| auto checkForSwiftCC = [&](unsigned paramIndex) { |
| // Only do this once. |
| if (hasCheckedSwiftCall) return; |
| hasCheckedSwiftCall = true; |
| if (EPI.ExtInfo.getCC() == CC_Swift) return; |
| S.Diag(getParamLoc(paramIndex), diag::err_swift_param_attr_not_swiftcall) |
| << getParameterABISpelling(EPI.ExtParameterInfos[paramIndex].getABI()); |
| }; |
| |
| for (size_t paramIndex = 0, numParams = paramTypes.size(); |
| paramIndex != numParams; ++paramIndex) { |
| switch (EPI.ExtParameterInfos[paramIndex].getABI()) { |
| // Nothing interesting to check for orindary-ABI parameters. |
| case ParameterABI::Ordinary: |
| continue; |
| |
| // swift_indirect_result parameters must be a prefix of the function |
| // arguments. |
| case ParameterABI::SwiftIndirectResult: |
| checkForSwiftCC(paramIndex); |
| if (paramIndex != 0 && |
| EPI.ExtParameterInfos[paramIndex - 1].getABI() |
| != ParameterABI::SwiftIndirectResult) { |
| S.Diag(getParamLoc(paramIndex), |
| diag::err_swift_indirect_result_not_first); |
| } |
| continue; |
| |
| case ParameterABI::SwiftContext: |
| checkForSwiftCC(paramIndex); |
| continue; |
| |
| // swift_error parameters must be preceded by a swift_context parameter. |
| case ParameterABI::SwiftErrorResult: |
| checkForSwiftCC(paramIndex); |
| if (paramIndex == 0 || |
| EPI.ExtParameterInfos[paramIndex - 1].getABI() != |
| ParameterABI::SwiftContext) { |
| S.Diag(getParamLoc(paramIndex), |
| diag::err_swift_error_result_not_after_swift_context); |
| } |
| continue; |
| } |
| llvm_unreachable("bad ABI kind"); |
| } |
| } |
| |
| QualType Sema::BuildFunctionType(QualType T, |
| MutableArrayRef<QualType> ParamTypes, |
| SourceLocation Loc, DeclarationName Entity, |
| const FunctionProtoType::ExtProtoInfo &EPI) { |
| bool Invalid = false; |
| |
| Invalid |= CheckFunctionReturnType(T, Loc); |
| |
| for (unsigned Idx = 0, Cnt = ParamTypes.size(); Idx < Cnt; ++Idx) { |
| // FIXME: Loc is too inprecise here, should use proper locations for args. |
| QualType ParamType = Context.getAdjustedParameterType(ParamTypes[Idx]); |
| if (ParamType->isVoidType()) { |
| Diag(Loc, diag::err_param_with_void_type); |
| Invalid = true; |
| } else if (ParamType->isHalfType() && !getLangOpts().HalfArgsAndReturns) { |
| // Disallow half FP arguments. |
| Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 0 << |
| FixItHint::CreateInsertion(Loc, "*"); |
| 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; |
| } |
| |
| if (EPI.ExtParameterInfos) { |
| checkExtParameterInfos(*this, ParamTypes, EPI, |
| [=](unsigned i) { return Loc; }); |
| } |
| |
| if (EPI.ExtInfo.getProducesResult()) { |
| // This is just a warning, so we can't fail to build if we see it. |
| checkNSReturnsRetainedReturnType(Loc, T); |
| } |
| |
| if (Invalid) |
| return QualType(); |
| |
| return Context.getFunctionType(T, ParamTypes, EPI); |
| } |
| |
| /// Build a member pointer type \c T Class::*. |
| /// |
| /// \param T the type to which the member pointer refers. |
| /// \param Class the class type into which the member pointer points. |
| /// \param Loc the location where this type begins |
| /// \param Entity the name of the entity that will have this member pointer type |
| /// |
| /// \returns a member pointer type, if successful, or a NULL type if there was |
| /// an error. |
| QualType Sema::BuildMemberPointerType(QualType T, QualType Class, |
| SourceLocation Loc, |
| DeclarationName Entity) { |
| // Verify that we're not building a pointer to pointer to function with |
| // exception specification. |
| if (CheckDistantExceptionSpec(T)) { |
| Diag(Loc, diag::err_distant_exception_spec); |
| return QualType(); |
| } |
| |
| // C++ 8.3.3p3: A pointer to member shall not point to ... a member |
| // with reference type, or "cv void." |
| if (T->isReferenceType()) { |
| Diag(Loc, diag::err_illegal_decl_mempointer_to_reference) |
| << getPrintableNameForEntity(Entity) << T; |
| return QualType(); |
| } |
| |
| if (T->isVoidType()) { |
| Diag(Loc, diag::err_illegal_decl_mempointer_to_void) |
| << getPrintableNameForEntity(Entity); |
| return QualType(); |
| } |
| |
| if (!Class->isDependentType() && !Class->isRecordType()) { |
| Diag(Loc, diag::err_mempointer_in_nonclass_type) << Class; |
| return QualType(); |
| } |
| |
| // Adjust the default free function calling convention to the default method |
| // calling convention. |
| bool IsCtorOrDtor = |
| (Entity.getNameKind() == DeclarationName::CXXConstructorName) || |
| (Entity.getNameKind() == DeclarationName::CXXDestructorName); |
| if (T->isFunctionType()) |
| adjustMemberFunctionCC(T, /*IsStatic=*/false, IsCtorOrDtor, Loc); |
| |
| return Context.getMemberPointerType(T, Class.getTypePtr()); |
| } |
| |
| /// Build a block pointer type. |
| /// |
| /// \param T The type to which we'll be building a block pointer. |
| /// |
| /// \param Loc The source location, used for diagnostics. |
| /// |
| /// \param Entity The name of the entity that involves the block pointer |
| /// type, if known. |
| /// |
| /// \returns A suitable block pointer type, if there are no |
| /// errors. Otherwise, returns a NULL type. |
| QualType Sema::BuildBlockPointerType(QualType T, |
| SourceLocation Loc, |
| DeclarationName Entity) { |
| if (!T->isFunctionType()) { |
| Diag(Loc, diag::err_nonfunction_block_type); |
| return QualType(); |
| } |
| |
| if (checkQualifiedFunction(*this, T, Loc, QFK_BlockPointer)) |
| return QualType(); |
| |
| return Context.getBlockPointerType(T); |
| } |
| |
| QualType Sema::GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo) { |
| QualType QT = Ty.get(); |
| if (QT.isNull()) { |
| if (TInfo) *TInfo = nullptr; |
| return QualType(); |
| } |
| |
| TypeSourceInfo *DI = nullptr; |
| if (const LocInfoType *LIT = dyn_cast<LocInfoType>(QT)) { |
| QT = LIT->getType(); |
| DI = LIT->getTypeSourceInfo(); |
| } |
| |
| if (TInfo) *TInfo = DI; |
| return QT; |
| } |
| |
| static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state, |
| Qualifiers::ObjCLifetime ownership, |
| unsigned chunkIndex); |
| |
| /// Given that this is the declaration of a parameter under ARC, |
| /// attempt to infer attributes and such for pointer-to-whatever |
| /// types. |
| static void inferARCWriteback(TypeProcessingState &state, |
| QualType &declSpecType) { |
| Sema &S = state.getSema(); |
| Declarator &declarator = state.getDeclarator(); |
| |
| // TODO: should we care about decl qualifiers? |
| |
| // Check whether the declarator has the expected form. We walk |
| // from the inside out in order to make the block logic work. |
| unsigned outermostPointerIndex = 0; |
| bool isBlockPointer = false; |
| unsigned numPointers = 0; |
| for (unsigned i = 0, e = declarator.getNumTypeObjects(); i != e; ++i) { |
| unsigned chunkIndex = i; |
| DeclaratorChunk &chunk = declarator.getTypeObject(chunkIndex); |
| switch (chunk.Kind) { |
| case DeclaratorChunk::Paren: |
| // Ignore parens. |
| break; |
| |
| case DeclaratorChunk::Reference: |
| case DeclaratorChunk::Pointer: |
| // Count the number of pointers. Treat references |
| // interchangeably as pointers; if they're mis-ordered, normal |
| // type building will discover that. |
| outermostPointerIndex = chunkIndex; |
| numPointers++; |
| break; |
| |
| case DeclaratorChunk::BlockPointer: |
| // If we have a pointer to block pointer, that's an acceptable |
| // indirect reference; anything else is not an application of |
| // the rules. |
| if (numPointers != 1) return; |
| numPointers++; |
| outermostPointerIndex = chunkIndex; |
| isBlockPointer = true; |
| |
| // We don't care about pointer structure in return values here. |
| goto done; |
| |
| case DeclaratorChunk::Array: // suppress if written (id[])? |
| case DeclaratorChunk::Function: |
| case DeclaratorChunk::MemberPointer: |
| case DeclaratorChunk::Pipe: |
| return; |
| } |
| } |
| done: |
| |
| // If we have *one* pointer, then we want to throw the qualifier on |
| // the declaration-specifiers, which means that it needs to be a |
| // retainable object type. |
| if (numPointers == 1) { |
| // If it's not a retainable object type, the rule doesn't apply. |
| if (!declSpecType->isObjCRetainableType()) return; |
| |
| // If it already has lifetime, don't do anything. |
| if (declSpecType.getObjCLifetime()) return; |
| |
| // Otherwise, modify the type in-place. |
| Qualifiers qs; |
| |
| if (declSpecType->isObjCARCImplicitlyUnretainedType()) |
| qs.addObjCLifetime(Qualifiers::OCL_ExplicitNone); |
| else |
| qs.addObjCLifetime(Qualifiers::OCL_Autoreleasing); |
| declSpecType = S.Context.getQualifiedType(declSpecType, qs); |
| |
| // If we have *two* pointers, then we want to throw the qualifier on |
| // the outermost pointer. |
| } else if (numPointers == 2) { |
| // If we don't have a block pointer, we need to check whether the |
| // declaration-specifiers gave us something that will turn into a |
| // retainable object pointer after we slap the first pointer on it. |
| if (!isBlockPointer && !declSpecType->isObjCObjectType()) |
| return; |
| |
| // Look for an explicit lifetime attribute there. |
| DeclaratorChunk &chunk = declarator.getTypeObject(outermostPointerIndex); |
| if (chunk.Kind != DeclaratorChunk::Pointer && |
| chunk.Kind != DeclaratorChunk::BlockPointer) |
| return; |
| for (const ParsedAttr &AL : chunk.getAttrs()) |
| if (AL.getKind() == ParsedAttr::AT_ObjCOwnership) |
| return; |
| |
| transferARCOwnershipToDeclaratorChunk(state, Qualifiers::OCL_Autoreleasing, |
| outermostPointerIndex); |
| |
| // Any other number of pointers/references does not trigger the rule. |
| } else return; |
| |
| // TODO: mark whether we did this inference? |
| } |
| |
| void Sema::diagnoseIgnoredQualifiers(unsigned DiagID, unsigned Quals, |
| SourceLocation FallbackLoc, |
| SourceLocation ConstQualLoc, |
| SourceLocation VolatileQualLoc, |
| SourceLocation RestrictQualLoc, |
| SourceLocation AtomicQualLoc, |
| SourceLocation UnalignedQualLoc) { |
| if (!Quals) |
| return; |
| |
| struct Qual { |
| const char *Name; |
| unsigned Mask; |
| SourceLocation Loc; |
| } const QualKinds[5] = { |
| { "const", DeclSpec::TQ_const, ConstQualLoc }, |
| { "volatile", DeclSpec::TQ_volatile, VolatileQualLoc }, |
| { "restrict", DeclSpec::TQ_restrict, RestrictQualLoc }, |
| { "__unaligned", DeclSpec::TQ_unaligned, UnalignedQualLoc }, |
| { "_Atomic", DeclSpec::TQ_atomic, AtomicQualLoc } |
| }; |
| |
| SmallString<32> QualStr; |
| unsigned NumQuals = 0; |
| SourceLocation Loc; |
| FixItHint FixIts[5]; |
| |
| // Build a string naming the redundant qualifiers. |
| for (auto &E : QualKinds) { |
| if (Quals & E.Mask) { |
| if (!QualStr.empty()) QualStr += ' '; |
| QualStr += E.Name; |
| |
| // If we have a location for the qualifier, offer a fixit. |
| SourceLocation QualLoc = E.Loc; |
| if (QualLoc.isValid()) { |
| FixIts[NumQuals] = FixItHint::CreateRemoval(QualLoc); |
| if (Loc.isInvalid() || |
| getSourceManager().isBeforeInTranslationUnit(QualLoc, Loc)) |
| Loc = QualLoc; |
| } |
| |
| ++NumQuals; |
| } |
| } |
| |
| Diag(Loc.isInvalid() ? FallbackLoc : Loc, DiagID) |
| << QualStr << NumQuals << FixIts[0] << FixIts[1] << FixIts[2] << FixIts[3]; |
| } |
| |
| // Diagnose pointless type qualifiers on the return type of a function. |
| static void diagnoseRedundantReturnTypeQualifiers(Sema &S, QualType RetTy, |
| Declarator &D, |
| unsigned FunctionChunkIndex) { |
| if (D.getTypeObject(FunctionChunkIndex).Fun.hasTrailingReturnType()) { |
| // FIXME: TypeSourceInfo doesn't preserve location information for |
| // qualifiers. |
| S.diagnoseIgnoredQualifiers(
|