diff options
Diffstat (limited to 'lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 814 |
1 files changed, 664 insertions, 150 deletions
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index f94c822b90f5..a5780a7d71fb 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" +#include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" @@ -27,10 +28,12 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.h" +#include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/MathExtras.h" + using namespace clang; using namespace sema; @@ -40,7 +43,7 @@ namespace AttributeLangSupport { Cpp, ObjC }; -} +} // end namespace AttributeLangSupport //===----------------------------------------------------------------------===// // Helper functions @@ -52,6 +55,7 @@ namespace AttributeLangSupport { static bool isFunctionOrMethod(const Decl *D) { return (D->getFunctionType() != nullptr) || isa<ObjCMethodDecl>(D); } + /// \brief Return true if the given decl has function type (function or /// function-typed variable) or an Objective-C method or a block. static bool isFunctionOrMethodOrBlock(const Decl *D) { @@ -801,6 +805,8 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D, } static void handleEnableIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { + S.Diag(Attr.getLoc(), diag::ext_clang_enable_if); + Expr *Cond = Attr.getArgAsExpr(0); if (!Cond->isTypeDependent()) { ExprResult Converted = S.PerformContextuallyConvertToBool(Cond); @@ -887,7 +893,6 @@ static void handleConsumableAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } - static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD, const AttributeList &Attr) { ASTContext &CurrContext = S.getASTContext(); @@ -905,7 +910,6 @@ static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD, return true; } - static void handleCallableWhenAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) @@ -944,7 +948,6 @@ static void handleCallableWhenAttr(Sema &S, Decl *D, States.size(), Attr.getAttributeSpellingListIndex())); } - static void handleParamTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { ParamTypestateAttr::ConsumedState ParamState; @@ -982,7 +985,6 @@ static void handleParamTypestateAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } - static void handleReturnTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { ReturnTypestateAttr::ConsumedState ReturnState; @@ -1031,7 +1033,6 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } - static void handleSetTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) return; @@ -1548,6 +1549,28 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } +static void handleIFuncAttr(Sema &S, Decl *D, const AttributeList &Attr) { + StringRef Str; + if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + return; + + // Aliases should be on declarations, not definitions. + const auto *FD = cast<FunctionDecl>(D); + if (FD->isThisDeclarationADefinition()) { + S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD << 1; + return; + } + // FIXME: it should be handled as a target specific attribute. + if (S.Context.getTargetInfo().getTriple().getObjectFormat() != + llvm::Triple::ELF) { + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + return; + } + + D->addAttr(::new (S.Context) IFuncAttr(Attr.getRange(), S.Context, Str, + Attr.getAttributeSpellingListIndex())); +} + static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { StringRef Str; if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str)) @@ -1557,17 +1580,20 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_darwin); return; } + if (S.Context.getTargetInfo().getTriple().isNVPTX()) { + S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_nvptx); + } // Aliases should be on declarations, not definitions. if (const auto *FD = dyn_cast<FunctionDecl>(D)) { if (FD->isThisDeclarationADefinition()) { - S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD; + S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD << 0; return; } } else { const auto *VD = cast<VarDecl>(D); if (VD->isThisDeclarationADefinition() && VD->isExternallyVisible()) { - S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << VD; + S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << VD << 0; return; } } @@ -1804,6 +1830,28 @@ static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } +static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) { + bool IsCXX1zAttr = Attr.isCXX11Attribute() && !Attr.getScopeName(); + + if (IsCXX1zAttr && isa<VarDecl>(D)) { + // The C++1z spelling of this attribute cannot be applied to a static data + // member per [dcl.attr.unused]p2. + if (cast<VarDecl>(D)->isStaticDataMember()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedForMaybeUnused; + return; + } + } + + // If this is spelled as the standard C++1z attribute, but not in C++1z, warn + // about using it as an extension. + if (!S.getLangOpts().CPlusPlus1z && IsCXX1zAttr) + S.Diag(Attr.getLoc(), diag::ext_cxx1z_attr) << Attr.getName(); + + D->addAttr(::new (S.Context) UnusedAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); +} + static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { uint32_t priority = ConstructorAttr::DefaultPriority; if (Attr.getNumArgs() && @@ -1910,11 +1958,14 @@ static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y, AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, IdentifierInfo *Platform, + bool Implicit, VersionTuple Introduced, VersionTuple Deprecated, VersionTuple Obsoleted, bool IsUnavailable, StringRef Message, + bool IsStrict, + StringRef Replacement, AvailabilityMergeKind AMK, unsigned AttrSpellingListIndex) { VersionTuple MergedIntroduced = Introduced; @@ -1952,14 +2003,14 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, // If there is an existing availability attribute for this platform that // is explicit and the new one is implicit use the explicit one and // discard the new implicit attribute. - if (OldAA->getRange().isValid() && Range.isInvalid()) { + if (!OldAA->isImplicit() && Implicit) { return nullptr; } // If there is an existing attribute for this platform that is implicit // and the new attribute is explicit then erase the old one and // continue processing the attributes. - if (Range.isValid() && OldAA->getRange().isInvalid()) { + if (!Implicit && OldAA->isImplicit()) { Attrs.erase(Attrs.begin() + i); --e; continue; @@ -2058,10 +2109,13 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, if (!checkAvailabilityAttr(*this, Range, Platform, MergedIntroduced, MergedDeprecated, MergedObsoleted) && !OverrideOrImpl) { - return ::new (Context) AvailabilityAttr(Range, Context, Platform, + auto *Avail = ::new (Context) AvailabilityAttr(Range, Context, Platform, Introduced, Deprecated, Obsoleted, IsUnavailable, Message, + IsStrict, Replacement, AttrSpellingListIndex); + Avail->setImplicit(Implicit); + return Avail; } return nullptr; } @@ -2088,16 +2142,23 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated(); AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted(); bool IsUnavailable = Attr.getUnavailableLoc().isValid(); + bool IsStrict = Attr.getStrictLoc().isValid(); StringRef Str; if (const StringLiteral *SE = dyn_cast_or_null<StringLiteral>(Attr.getMessageExpr())) Str = SE->getString(); + StringRef Replacement; + if (const StringLiteral *SE = + dyn_cast_or_null<StringLiteral>(Attr.getReplacementExpr())) + Replacement = SE->getString(); AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, Attr.getRange(), II, + false/*Implicit*/, Introduced.Version, Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, + IsStrict, Replacement, Sema::AMK_None, Index); if (NewAttr) @@ -2136,12 +2197,15 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version); AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, - SourceRange(), + Attr.getRange(), NewII, + true/*Implicit*/, NewIntroduced, NewDeprecated, NewObsoleted, IsUnavailable, Str, + IsStrict, + Replacement, Sema::AMK_None, Index); if (NewAttr) @@ -2158,12 +2222,15 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, if (NewII) { AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, - SourceRange(), + Attr.getRange(), NewII, + true/*Implicit*/, Introduced.Version, Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, + IsStrict, + Replacement, Sema::AMK_None, Index); if (NewAttr) @@ -2455,6 +2522,12 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) return; } + // If this is spelled as the standard C++1z attribute, but not in C++1z, warn + // about using it as an extension. + if (!S.getLangOpts().CPlusPlus1z && Attr.isCXX11Attribute() && + !Attr.getScopeName()) + S.Diag(Attr.getLoc(), diag::ext_cxx1z_attr) << Attr.getName(); + D->addAttr(::new (S.Context) WarnUnusedResultAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); @@ -2611,7 +2684,6 @@ static void handleTargetAttr(Sema &S, Decl *D, const AttributeList &Attr) { D->addAttr(NewAttr); } - static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { VarDecl *VD = cast<VarDecl>(D); if (!VD->hasLocalStorage()) { @@ -3069,7 +3141,6 @@ void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, // Save dependent expressions in the AST to be instantiated. D->addAttr(::new (Context) AlignValueAttr(TmpAttr)); - return; } static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -3293,6 +3364,8 @@ bool Sema::checkMSInheritanceAttrOnDefinition( /// attribute. static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth, bool &IntegerMode, bool &ComplexMode) { + IntegerMode = true; + ComplexMode = false; switch (Str.size()) { case 2: switch (Str[0]) { @@ -3328,7 +3401,7 @@ static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth, // FIXME: glibc uses 'word' to define register_t; this is narrower than a // pointer on PIC16 and other embedded platforms. if (Str == "word") - DestWidth = S.Context.getTargetInfo().getPointerWidth(0); + DestWidth = S.Context.getTargetInfo().getRegisterWidth(); else if (Str == "byte") DestWidth = S.Context.getTargetInfo().getCharWidth(); break; @@ -3359,9 +3432,15 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { } IdentifierInfo *Name = Attr.getArgAsIdent(0)->Ident; - StringRef Str = Name->getName(); + S.AddModeAttr(Attr.getRange(), D, Name, Attr.getAttributeSpellingListIndex()); +} + +void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, + unsigned SpellingListIndex, bool InInstantiation) { + StringRef Str = Name->getName(); normalizeName(Str); + SourceLocation AttrLoc = AttrRange.getBegin(); unsigned DestWidth = 0; bool IntegerMode = true; @@ -3377,25 +3456,43 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (VectorStringLength && !Str.substr(1, VectorStringLength).getAsInteger(10, VectorSize) && VectorSize.isPowerOf2()) { - parseModeAttrArg(S, Str.substr(VectorStringLength + 1), DestWidth, + parseModeAttrArg(*this, Str.substr(VectorStringLength + 1), DestWidth, IntegerMode, ComplexMode); - S.Diag(Attr.getLoc(), diag::warn_vector_mode_deprecated); + // Avoid duplicate warning from template instantiation. + if (!InInstantiation) + Diag(AttrLoc, diag::warn_vector_mode_deprecated); } else { VectorSize = 0; } } if (!VectorSize) - parseModeAttrArg(S, Str, DestWidth, IntegerMode, ComplexMode); + parseModeAttrArg(*this, Str, DestWidth, IntegerMode, ComplexMode); + + // FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t + // and friends, at least with glibc. + // FIXME: Make sure floating-point mappings are accurate + // FIXME: Support XF and TF types + if (!DestWidth) { + Diag(AttrLoc, diag::err_machine_mode) << 0 /*Unknown*/ << Name; + return; + } QualType OldTy; if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) OldTy = TD->getUnderlyingType(); - else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) - OldTy = VD->getType(); - else { - S.Diag(D->getLocation(), diag::err_attr_wrong_decl) - << Attr.getName() << Attr.getRange(); + else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) { + // Something like 'typedef enum { X } __attribute__((mode(XX))) T;'. + // Try to get type from enum declaration, default to int. + OldTy = ED->getIntegerType(); + if (OldTy.isNull()) + OldTy = Context.IntTy; + } else + OldTy = cast<ValueDecl>(D)->getType(); + + if (OldTy->isDependentType()) { + D->addAttr(::new (Context) + ModeAttr(AttrRange, Context, Name, SpellingListIndex)); return; } @@ -3405,91 +3502,83 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (const VectorType *VT = OldTy->getAs<VectorType>()) OldElemTy = VT->getElementType(); - if (!OldElemTy->getAs<BuiltinType>() && !OldElemTy->isComplexType()) - S.Diag(Attr.getLoc(), diag::err_mode_not_primitive); + // GCC allows 'mode' attribute on enumeration types (even incomplete), except + // for vector modes. So, 'enum X __attribute__((mode(QI)));' forms a complete + // type, 'enum { A } __attribute__((mode(V4SI)))' is rejected. + if ((isa<EnumDecl>(D) || OldElemTy->getAs<EnumType>()) && + VectorSize.getBoolValue()) { + Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << AttrRange; + return; + } + bool IntegralOrAnyEnumType = + OldElemTy->isIntegralOrEnumerationType() || OldElemTy->getAs<EnumType>(); + + if (!OldElemTy->getAs<BuiltinType>() && !OldElemTy->isComplexType() && + !IntegralOrAnyEnumType) + Diag(AttrLoc, diag::err_mode_not_primitive); else if (IntegerMode) { - if (!OldElemTy->isIntegralOrEnumerationType()) - S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); + if (!IntegralOrAnyEnumType) + Diag(AttrLoc, diag::err_mode_wrong_type); } else if (ComplexMode) { if (!OldElemTy->isComplexType()) - S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); + Diag(AttrLoc, diag::err_mode_wrong_type); } else { if (!OldElemTy->isFloatingType()) - S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); - } - - // FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t - // and friends, at least with glibc. - // FIXME: Make sure floating-point mappings are accurate - // FIXME: Support XF and TF types - if (!DestWidth) { - S.Diag(Attr.getLoc(), diag::err_machine_mode) << 0 /*Unknown*/ << Name; - return; + Diag(AttrLoc, diag::err_mode_wrong_type); } QualType NewElemTy; if (IntegerMode) - NewElemTy = S.Context.getIntTypeForBitwidth( - DestWidth, OldElemTy->isSignedIntegerType()); + NewElemTy = Context.getIntTypeForBitwidth(DestWidth, + OldElemTy->isSignedIntegerType()); else - NewElemTy = S.Context.getRealTypeForBitwidth(DestWidth); + NewElemTy = Context.getRealTypeForBitwidth(DestWidth); if (NewElemTy.isNull()) { - S.Diag(Attr.getLoc(), diag::err_machine_mode) << 1 /*Unsupported*/ << Name; + Diag(AttrLoc, diag::err_machine_mode) << 1 /*Unsupported*/ << Name; return; } if (ComplexMode) { - NewElemTy = S.Context.getComplexType(NewElemTy); + NewElemTy = Context.getComplexType(NewElemTy); } QualType NewTy = NewElemTy; if (VectorSize.getBoolValue()) { - NewTy = S.Context.getVectorType(NewTy, VectorSize.getZExtValue(), - VectorType::GenericVector); + NewTy = Context.getVectorType(NewTy, VectorSize.getZExtValue(), + VectorType::GenericVector); } else if (const VectorType *OldVT = OldTy->getAs<VectorType>()) { // Complex machine mode does not support base vector types. if (ComplexMode) { - S.Diag(Attr.getLoc(), diag::err_complex_mode_vector_type); + Diag(AttrLoc, diag::err_complex_mode_vector_type); return; } - unsigned NumElements = S.Context.getTypeSize(OldElemTy) * + unsigned NumElements = Context.getTypeSize(OldElemTy) * OldVT->getNumElements() / - S.Context.getTypeSize(NewElemTy); + Context.getTypeSize(NewElemTy); NewTy = - S.Context.getVectorType(NewElemTy, NumElements, OldVT->getVectorKind()); + Context.getVectorType(NewElemTy, NumElements, OldVT->getVectorKind()); } if (NewTy.isNull()) { - S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); + Diag(AttrLoc, diag::err_mode_wrong_type); return; } // Install the new type. if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) TD->setModedTypeSourceInfo(TD->getTypeSourceInfo(), NewTy); + else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) + ED->setIntegerType(NewTy); else cast<ValueDecl>(D)->setType(NewTy); - D->addAttr(::new (S.Context) - ModeAttr(Attr.getRange(), S.Context, Name, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (Context) + ModeAttr(AttrRange, Context, Name, SpellingListIndex)); } static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { - if (!VD->hasGlobalStorage()) - S.Diag(Attr.getLoc(), - diag::warn_attribute_requires_functions_or_static_globals) - << Attr.getName(); - } else if (!isFunctionOrMethod(D)) { - S.Diag(Attr.getLoc(), - diag::warn_attribute_requires_functions_or_static_globals) - << Attr.getName(); - return; - } - D->addAttr(::new (S.Context) NoDebugAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); @@ -3622,11 +3711,21 @@ static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { : FixItHint()); return; } + if (const auto *Method = dyn_cast<CXXMethodDecl>(FD)) { + if (Method->isInstance()) { + S.Diag(Method->getLocStart(), diag::err_kern_is_nonstatic_method) + << Method; + return; + } + S.Diag(Method->getLocStart(), diag::warn_kern_is_method) << Method; + } + // Only warn for "inline" when compiling for host, to cut down on noise. + if (FD->isInlineSpecified() && !S.getLangOpts().CUDAIsDevice) + S.Diag(FD->getLocStart(), diag::warn_kern_is_inline) << FD; D->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); - } static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -3682,6 +3781,11 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { PascalAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); return; + case AttributeList::AT_SwiftCall: + D->addAttr(::new (S.Context) + SwiftCallAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); + return; case AttributeList::AT_VectorCall: D->addAttr(::new (S.Context) VectorCallAttr(Attr.getRange(), S.Context, @@ -3720,7 +3824,14 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { IntelOclBiccAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); return; - + case AttributeList::AT_PreserveMost: + D->addAttr(::new (S.Context) PreserveMostAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + return; + case AttributeList::AT_PreserveAll: + D->addAttr(::new (S.Context) PreserveAllAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + return; default: llvm_unreachable("unexpected attribute kind"); } @@ -3731,6 +3842,11 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, if (attr.isInvalid()) return true; + if (attr.hasProcessingCache()) { + CC = (CallingConv) attr.getProcessingCache(); + return false; + } + unsigned ReqArgs = attr.getKind() == AttributeList::AT_Pcs ? 1 : 0; if (!checkAttributeNumArgs(*this, attr, ReqArgs)) { attr.setInvalid(); @@ -3744,6 +3860,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, case AttributeList::AT_StdCall: CC = CC_X86StdCall; break; case AttributeList::AT_ThisCall: CC = CC_X86ThisCall; break; case AttributeList::AT_Pascal: CC = CC_X86Pascal; break; + case AttributeList::AT_SwiftCall: CC = CC_Swift; break; case AttributeList::AT_VectorCall: CC = CC_X86VectorCall; break; case AttributeList::AT_MSABI: CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C : @@ -3772,6 +3889,8 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, return true; } case AttributeList::AT_IntelOclBicc: CC = CC_IntelOclBicc; break; + case AttributeList::AT_PreserveMost: CC = CC_PreserveMost; break; + case AttributeList::AT_PreserveAll: CC = CC_PreserveAll; break; default: llvm_unreachable("unexpected attribute kind"); } @@ -3783,16 +3902,108 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, // This convention is not valid for the target. Use the default function or // method calling convention. - TargetInfo::CallingConvMethodType MT = TargetInfo::CCMT_Unknown; - if (FD) - MT = FD->isCXXInstanceMember() ? TargetInfo::CCMT_Member : - TargetInfo::CCMT_NonMember; - CC = TI.getDefaultCallingConv(MT); + bool IsCXXMethod = false, IsVariadic = false; + if (FD) { + IsCXXMethod = FD->isCXXInstanceMember(); + IsVariadic = FD->isVariadic(); + } + CC = Context.getDefaultCallingConvention(IsVariadic, IsCXXMethod); } + attr.setProcessingCache((unsigned) CC); return false; } +/// Pointer-like types in the default address space. +static bool isValidSwiftContextType(QualType type) { + if (!type->hasPointerRepresentation()) + return type->isDependentType(); + return type->getPointeeType().getAddressSpace() == 0; +} + +/// Pointers and references in the default address space. +static bool isValidSwiftIndirectResultType(QualType type) { + if (auto ptrType = type->getAs<PointerType>()) { + type = ptrType->getPointeeType(); + } else if (auto refType = type->getAs<ReferenceType>()) { + type = refType->getPointeeType(); + } else { + return type->isDependentType(); + } + return type.getAddressSpace() == 0; +} + +/// Pointers and references to pointers in the default address space. +static bool isValidSwiftErrorResultType(QualType type) { + if (auto ptrType = type->getAs<PointerType>()) { + type = ptrType->getPointeeType(); + } else if (auto refType = type->getAs<ReferenceType>()) { + type = refType->getPointeeType(); + } else { + return type->isDependentType(); + } + if (!type.getQualifiers().empty()) + return false; + return isValidSwiftContextType(type); +} + +static void handleParameterABIAttr(Sema &S, Decl *D, const AttributeList &attr, + ParameterABI abi) { + S.AddParameterABIAttr(attr.getRange(), D, abi, + attr.getAttributeSpellingListIndex()); +} + +void Sema::AddParameterABIAttr(SourceRange range, Decl *D, ParameterABI abi, + unsigned spellingIndex) { + + QualType type = cast<ParmVarDecl>(D)->getType(); + + if (auto existingAttr = D->getAttr<ParameterABIAttr>()) { + if (existingAttr->getABI() != abi) { + Diag(range.getBegin(), diag::err_attributes_are_not_compatible) + << getParameterABISpelling(abi) << existingAttr; + Diag(existingAttr->getLocation(), diag::note_conflicting_attribute); + return; + } + } + + switch (abi) { + case ParameterABI::Ordinary: + llvm_unreachable("explicit attribute for ordinary parameter ABI?"); + + case ParameterABI::SwiftContext: + if (!isValidSwiftContextType(type)) { + Diag(range.getBegin(), diag::err_swift_abi_parameter_wrong_type) + << getParameterABISpelling(abi) + << /*pointer to pointer */ 0 << type; + } + D->addAttr(::new (Context) + SwiftContextAttr(range, Context, spellingIndex)); + return; + + case ParameterABI::SwiftErrorResult: + if (!isValidSwiftErrorResultType(type)) { + Diag(range.getBegin(), diag::err_swift_abi_parameter_wrong_type) + << getParameterABISpelling(abi) + << /*pointer to pointer */ 1 << type; + } + D->addAttr(::new (Context) + SwiftErrorResultAttr(range, Context, spellingIndex)); + return; + + case ParameterABI::SwiftIndirectResult: + if (!isValidSwiftIndirectResultType(type)) { + Diag(range.getBegin(), diag::err_swift_abi_parameter_wrong_type) + << getParameterABISpelling(abi) + << /*pointer*/ 0 << type; + } + D->addAttr(::new (Context) + SwiftIndirectResultAttr(range, Context, spellingIndex)); + return; + } + llvm_unreachable("bad parameter ABI attribute"); +} + /// Checks a regparm attribute, returning true if it is ill-formed and /// otherwise setting numParams to the appropriate value. bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { @@ -3829,49 +4040,60 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { return false; } -// Checks whether an argument of launch_bounds attribute is acceptable -// May output an error. -static bool checkLaunchBoundsArgument(Sema &S, Expr *E, - const CUDALaunchBoundsAttr &Attr, - const unsigned Idx) { - +// Checks whether an argument of launch_bounds attribute is +// acceptable, performs implicit conversion to Rvalue, and returns +// non-nullptr Expr result on success. Otherwise, it returns nullptr +// and may output an error. +static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E, + const CUDALaunchBoundsAttr &Attr, + const unsigned Idx) { if (S.DiagnoseUnexpandedParameterPack(E)) - return false; + return nullptr; // Accept template arguments for now as they depend on something else. // We'll get to check them when they eventually get instantiated. if (E->isValueDependent()) - return true; + return E; llvm::APSInt I(64); if (!E->isIntegerConstantExpr(I, S.Context)) { S.Diag(E->getExprLoc(), diag::err_attribute_argument_n_type) << &Attr << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange(); - return false; + return nullptr; } // Make sure we can fit it in 32 bits. if (!I.isIntN(32)) { S.Diag(E->getExprLoc(), diag::err_ice_too_large) << I.toString(10, false) << 32 << /* Unsigned */ 1; - return false; + return nullptr; } if (I < 0) S.Diag(E->getExprLoc(), diag::warn_attribute_argument_n_negative) << &Attr << Idx << E->getSourceRange(); - return true; + // We may need to perform implicit conversion of the argument. + InitializedEntity Entity = InitializedEntity::InitializeParameter( + S.Context, S.Context.getConstType(S.Context.IntTy), /*consume*/ false); + ExprResult ValArg = S.PerformCopyInitialization(Entity, SourceLocation(), E); + assert(!ValArg.isInvalid() && + "Unexpected PerformCopyInitialization() failure."); + + return ValArg.getAs<Expr>(); } void Sema::AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads, Expr *MinBlocks, unsigned SpellingListIndex) { CUDALaunchBoundsAttr TmpAttr(AttrRange, Context, MaxThreads, MinBlocks, SpellingListIndex); - - if (!checkLaunchBoundsArgument(*this, MaxThreads, TmpAttr, 0)) + MaxThreads = makeLaunchBoundsArgExpr(*this, MaxThreads, TmpAttr, 0); + if (MaxThreads == nullptr) return; - if (MinBlocks && !checkLaunchBoundsArgument(*this, MinBlocks, TmpAttr, 1)) - return; + if (MinBlocks) { + MinBlocks = makeLaunchBoundsArgExpr(*this, MinBlocks, TmpAttr, 1); + if (MinBlocks == nullptr) + return; + } D->addAttr(::new (Context) CUDALaunchBoundsAttr( AttrRange, Context, MaxThreads, MinBlocks, SpellingListIndex)); @@ -3977,6 +4199,7 @@ static bool isValidSubjectOfNSAttribute(Sema &S, QualType type) { type->isObjCObjectPointerType() || S.Context.isObjCNSObjectType(type); } + static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) { return type->isDependentType() || type->isPointerType() || @@ -3984,36 +4207,49 @@ static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) { } static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) { + S.AddNSConsumedAttr(Attr.getRange(), D, Attr.getAttributeSpellingListIndex(), + Attr.getKind() == AttributeList::AT_NSConsumed, + /*template instantiation*/ false); +} + +void Sema::AddNSConsumedAttr(SourceRange attrRange, Decl *D, + unsigned spellingIndex, bool isNSConsumed, + bool isTemplateInstantiation) { ParmVarDecl *param = cast<ParmVarDecl>(D); - bool typeOK, cf; + bool typeOK; - if (Attr.getKind() == AttributeList::AT_NSConsumed) { - typeOK = isValidSubjectOfNSAttribute(S, param->getType()); - cf = false; + if (isNSConsumed) { + typeOK = isValidSubjectOfNSAttribute(*this, param->getType()); } else { - typeOK = isValidSubjectOfCFAttribute(S, param->getType()); - cf = true; + typeOK = isValidSubjectOfCFAttribute(*this, param->getType()); } if (!typeOK) { - S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) - << Attr.getRange() << Attr.getName() << cf; - return; - } - - if (cf) - param->addAttr(::new (S.Context) - CFConsumedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + // These attributes are normally just advisory, but in ARC, ns_consumed + // is significant. Allow non-dependent code to contain inappropriate + // attributes even in ARC, but require template instantiations to be + // set up correctly. + Diag(D->getLocStart(), + (isTemplateInstantiation && isNSConsumed && + getLangOpts().ObjCAutoRefCount + ? diag::err_ns_attribute_wrong_parameter_type + : diag::warn_ns_attribute_wrong_parameter_type)) + << attrRange + << (isNSConsumed ? "ns_consumed" : "cf_consumed") + << (isNSConsumed ? /*objc pointers*/ 0 : /*cf pointers*/ 1); + return; + } + + if (isNSConsumed) + param->addAttr(::new (Context) + NSConsumedAttr(attrRange, Context, spellingIndex)); else - param->addAttr(::new (S.Context) - NSConsumedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + param->addAttr(::new (Context) + CFConsumedAttr(attrRange, Context, spellingIndex)); } static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - QualType returnType; if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) @@ -4287,10 +4523,9 @@ static void handleObjCRuntimeName(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } -// when a user wants to use objc_boxable with a union or struct -// but she doesn't have access to the declaration (legacy/third-party code) -// then she can 'enable' this feature via trick with a typedef -// e.g.: +// When a user wants to use objc_boxable with a union or struct +// but they don't have access to the declaration (legacy/third-party code) +// then they can 'enable' this feature with a typedef: // typedef struct __attribute((objc_boxable)) legacy_struct legacy_struct; static void handleObjCBoxable(Sema &S, Decl *D, const AttributeList &Attr) { bool notify = false; @@ -4423,8 +4658,10 @@ static void handleMSInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) D, Attr.getRange(), /*BestCase=*/true, Attr.getAttributeSpellingListIndex(), (MSInheritanceAttr::Spelling)Attr.getSemanticSpelling()); - if (IA) + if (IA) { D->addAttr(IA); + S.Consumer.AssignInheritanceModel(cast<CXXRecordDecl>(D)); + } } static void handleDeclspecThreadAttr(Sema &S, Decl *D, @@ -4446,6 +4683,38 @@ static void handleDeclspecThreadAttr(Sema &S, Decl *D, Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); } +static void handleAbiTagAttr(Sema &S, Decl *D, const AttributeList &Attr) { + SmallVector<StringRef, 4> Tags; + for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) { + StringRef Tag; + if (!S.checkStringLiteralArgumentAttr(Attr, I, Tag)) + return; + Tags.push_back(Tag); + } + + if (const auto *NS = dyn_cast<NamespaceDecl>(D)) { + if (!NS->isInline()) { + S.Diag(Attr.getLoc(), diag::warn_attr_abi_tag_namespace) << 0; + return; + } + if (NS->isAnonymousNamespace()) { + S.Diag(Attr.getLoc(), diag::warn_attr_abi_tag_namespace) << 1; + return; + } + if (Attr.getNumArgs() == 0) + Tags.push_back(NS->getName()); + } else if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + + // Store tags sorted and without duplicates. + std::sort(Tags.begin(), Tags.end()); + Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end()); + + D->addAttr(::new (S.Context) + AbiTagAttr(Attr.getRange(), S.Context, Tags.data(), Tags.size(), + Attr.getAttributeSpellingListIndex())); +} + static void handleARMInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Check the attribute arguments. @@ -4570,17 +4839,90 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, Attr.getLoc(), S.Context, Kind, Attr.getAttributeSpellingListIndex())); } +static void handleAnyX86InterruptAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + // Semantic checks for a function with the 'interrupt' attribute. + // a) Must be a function. + // b) Must have the 'void' return type. + // c) Must take 1 or 2 arguments. + // d) The 1st argument must be a pointer. + // e) The 2nd argument (if any) must be an unsigned integer. + if (!isFunctionOrMethod(D) || !hasFunctionProto(D) || isInstanceMethod(D) || + CXXMethodDecl::isStaticOverloadedOperator( + cast<NamedDecl>(D)->getDeclName().getCXXOverloadedOperator())) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionWithProtoType; + return; + } + // Interrupt handler must have void return type. + if (!getFunctionOrMethodResultType(D)->isVoidType()) { + S.Diag(getFunctionOrMethodResultSourceRange(D).getBegin(), + diag::err_anyx86_interrupt_attribute) + << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86 + ? 0 + : 1) + << 0; + return; + } + // Interrupt handler must have 1 or 2 parameters. + unsigned NumParams = getFunctionOrMethodNumParams(D); + if (NumParams < 1 || NumParams > 2) { + S.Diag(D->getLocStart(), diag::err_anyx86_interrupt_attribute) + << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86 + ? 0 + : 1) + << 1; + return; + } + // The first argument must be a pointer. + if (!getFunctionOrMethodParamType(D, 0)->isPointerType()) { + S.Diag(getFunctionOrMethodParamRange(D, 0).getBegin(), + diag::err_anyx86_interrupt_attribute) + << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86 + ? 0 + : 1) + << 2; + return; + } + // The second argument, if present, must be an unsigned integer. + unsigned TypeSize = + S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64 + ? 64 + : 32; + if (NumParams == 2 && + (!getFunctionOrMethodParamType(D, 1)->isUnsignedIntegerType() || + S.Context.getTypeSize(getFunctionOrMethodParamType(D, 1)) != TypeSize)) { + S.Diag(getFunctionOrMethodParamRange(D, 1).getBegin(), + diag::err_anyx86_interrupt_attribute) + << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86 + ? 0 + : 1) + << 3 << S.Context.getIntTypeForBitwidth(TypeSize, /*Signed=*/false); + return; + } + D->addAttr(::new (S.Context) AnyX86InterruptAttr( + Attr.getLoc(), S.Context, Attr.getAttributeSpellingListIndex())); + D->addAttr(UsedAttr::CreateImplicit(S.Context)); +} + static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Dispatch the interrupt attribute based on the current target. - if (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::msp430) + switch (S.Context.getTargetInfo().getTriple().getArch()) { + case llvm::Triple::msp430: handleMSP430InterruptAttr(S, D, Attr); - else if (S.Context.getTargetInfo().getTriple().getArch() == - llvm::Triple::mipsel || - S.Context.getTargetInfo().getTriple().getArch() == - llvm::Triple::mips) + break; + case llvm::Triple::mipsel: + case llvm::Triple::mips: handleMipsInterruptAttr(S, D, Attr); - else + break; + case llvm::Triple::x86: + case llvm::Triple::x86_64: + handleAnyX86InterruptAttr(S, D, Attr); + break; + default: handleARMInterruptAttr(S, D, Attr); + break; + } } static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, @@ -4634,6 +4976,24 @@ static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } +static void handleLayoutVersion(Sema &S, Decl *D, const AttributeList &Attr) { + uint32_t Version; + Expr *VersionExpr = static_cast<Expr *>(Attr.getArgAsExpr(0)); + if (!checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), Version)) + return; + + // TODO: Investigate what happens with the next major version of MSVC. + if (Version != LangOptions::MSVC2015) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) + << Attr.getName() << Version << VersionExpr->getSourceRange(); + return; + } + + D->addAttr(::new (S.Context) + LayoutVersionAttr(Attr.getRange(), S.Context, Version, + Attr.getAttributeSpellingListIndex())); +} + DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex) { if (D->hasAttr<DLLExportAttr>()) { @@ -4827,19 +5187,34 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) { } } + // Handle the cases where the attribute has a text message. + StringRef Str, Replacement; + if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0) && + !S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + return; + + // Only support a single optional message for Declspec and CXX11. + if (Attr.isDeclspecAttribute() || Attr.isCXX11Attribute()) + checkAttributeAtMostNumArgs(S, Attr, 1); + else if (Attr.isArgExpr(1) && Attr.getArgAsExpr(1) && + !S.checkStringLiteralArgumentAttr(Attr, 1, Replacement)) + return; + if (!S.getLangOpts().CPlusPlus14) if (Attr.isCXX11Attribute() && !(Attr.hasScope() && Attr.getScopeName()->isStr("gnu"))) - S.Diag(Attr.getLoc(), diag::ext_deprecated_attr_is_a_cxx14_extension); + S.Diag(Attr.getLoc(), diag::ext_cxx14_attr) << Attr.getName(); - handleAttrWithMessage<DeprecatedAttr>(S, D, Attr); + D->addAttr(::new (S.Context) DeprecatedAttr(Attr.getRange(), S.Context, Str, + Replacement, + Attr.getAttributeSpellingListIndex())); } static void handleNoSanitizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) return; - std::vector<std::string> Sanitizers; + std::vector<StringRef> Sanitizers; for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) { StringRef SanitizerName; @@ -4863,8 +5238,8 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D, const AttributeList &Attr) { StringRef AttrName = Attr.getName()->getName(); normalizeName(AttrName); - std::string SanitizerName = - llvm::StringSwitch<std::string>(AttrName) + StringRef SanitizerName = + llvm::StringSwitch<StringRef>(AttrName) .Case("no_address_safety_analysis", "address") .Case("no_sanitize_address", "address") .Case("no_sanitize_thread", "thread") @@ -4882,6 +5257,15 @@ static void handleInternalLinkageAttr(Sema &S, Decl *D, D->addAttr(Internal); } +static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (S.LangOpts.OpenCLVersion != 200) + S.Diag(Attr.getLoc(), diag::err_attribute_requires_opencl_version) + << Attr.getName() << "2.0" << 0; + else + S.Diag(Attr.getLoc(), diag::warn_opencl_attr_deprecated_ignored) + << Attr.getName() << "2.0"; +} + /// Handles semantic checking for features that are common to all attributes, /// such as checking whether a parameter was properly specified, or the correct /// number of arguments were passed, etc. @@ -4923,6 +5307,40 @@ static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D, return false; } +static void handleOpenCLAccessAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (D->isInvalidDecl()) + return; + + // Check if there is only one access qualifier. + if (D->hasAttr<OpenCLAccessAttr>()) { + S.Diag(Attr.getLoc(), diag::err_opencl_multiple_access_qualifiers) + << D->getSourceRange(); + D->setInvalidDecl(true); + return; + } + + // OpenCL v2.0 s6.6 - read_write can be used for image types to specify that an + // image object can be read and written. + // OpenCL v2.0 s6.13.6 - A kernel cannot read from and write to the same pipe + // object. Using the read_write (or __read_write) qualifier with the pipe + // qualifier is a compilation error. + if (const ParmVarDecl *PDecl = dyn_cast<ParmVarDecl>(D)) { + const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr(); + if (Attr.getName()->getName().find("read_write") != StringRef::npos) { + if (S.getLangOpts().OpenCLVersion < 200 || DeclTy->isPipeType()) { + S.Diag(Attr.getLoc(), diag::err_opencl_invalid_read_write) + << Attr.getName() << PDecl->getType() << DeclTy->isImageType(); + D->setInvalidDecl(true); + return; + } + } + } + + D->addAttr(::new (S.Context) OpenCLAccessAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); +} + //===----------------------------------------------------------------------===// // Top Level Sema Entry Points //===----------------------------------------------------------------------===// @@ -4958,8 +5376,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, switch (Attr.getKind()) { default: - // Type attributes are handled elsewhere; silently move on. - assert(Attr.isTypeAttr() && "Non-type attribute not handled"); + if (!Attr.isStmtAttr()) { + // Type attributes are handled elsewhere; silently move on. + assert(Attr.isTypeAttr() && "Non-type attribute not handled"); + break; + } + S.Diag(Attr.getLoc(), diag::err_stmt_attribute_invalid_on_decl) + << Attr.getName() << D->getLocation(); break; case AttributeList::AT_Interrupt: handleInterruptAttr(S, D, Attr); @@ -4993,6 +5416,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_IBOutletCollection: handleIBOutletCollection(S, D, Attr); break; + case AttributeList::AT_IFunc: + handleIFuncAttr(S, D, Attr); + break; case AttributeList::AT_Alias: handleAliasAttr(S, D, Attr); break; @@ -5141,53 +5567,45 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_VecReturn: handleVecReturnAttr(S, D, Attr); break; - case AttributeList::AT_ObjCOwnership: handleObjCOwnershipAttr(S, D, Attr); break; case AttributeList::AT_ObjCPreciseLifetime: handleObjCPreciseLifetimeAttr(S, D, Attr); break; - case AttributeList::AT_ObjCReturnsInnerPointer: handleObjCReturnsInnerPointerAttr(S, D, Attr); break; - case AttributeList::AT_ObjCRequiresSuper: handleObjCRequiresSuperAttr(S, D, Attr); break; - case AttributeList::AT_ObjCBridge: handleObjCBridgeAttr(S, scope, D, Attr); break; - case AttributeList::AT_ObjCBridgeMutable: handleObjCBridgeMutableAttr(S, scope, D, Attr); break; - case AttributeList::AT_ObjCBridgeRelated: handleObjCBridgeRelatedAttr(S, scope, D, Attr); break; - case AttributeList::AT_ObjCDesignatedInitializer: handleObjCDesignatedInitializer(S, D, Attr); break; - case AttributeList::AT_ObjCRuntimeName: handleObjCRuntimeName(S, D, Attr); break; - + case AttributeList::AT_ObjCRuntimeVisible: + handleSimpleAttribute<ObjCRuntimeVisibleAttr>(S, D, Attr); + break; case AttributeList::AT_ObjCBoxable: handleObjCBoxable(S, D, Attr); break; - case AttributeList::AT_CFAuditedTransfer: handleCFAuditedTransferAttr(S, D, Attr); break; case AttributeList::AT_CFUnknownTransfer: handleCFUnknownTransferAttr(S, D, Attr); break; - case AttributeList::AT_CFConsumed: case AttributeList::AT_NSConsumed: handleNSConsumedAttr(S, D, Attr); @@ -5195,7 +5613,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_NSConsumesSelf: handleSimpleAttribute<NSConsumesSelfAttr>(S, D, Attr); break; - case AttributeList::AT_NSReturnsAutoreleased: case AttributeList::AT_NSReturnsNotRetained: case AttributeList::AT_CFReturnsNotRetained: @@ -5212,11 +5629,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_VecTypeHint: handleVecTypeHint(S, D, Attr); break; - case AttributeList::AT_InitPriority: handleInitPriorityAttr(S, D, Attr); break; - case AttributeList::AT_Packed: handlePackedAttr(S, D, Attr); break; @@ -5242,7 +5657,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleSimpleAttribute<ObjCRequiresPropertyDefsAttr>(S, D, Attr); break; case AttributeList::AT_Unused: - handleSimpleAttribute<UnusedAttr>(S, D, Attr); + handleUnusedAttr(S, D, Attr); break; case AttributeList::AT_ReturnsTwice: handleSimpleAttribute<ReturnsTwiceAttr>(S, D, Attr); @@ -5324,24 +5739,48 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_FastCall: case AttributeList::AT_ThisCall: case AttributeList::AT_Pascal: + case AttributeList::AT_SwiftCall: case AttributeList::AT_VectorCall: case AttributeList::AT_MSABI: case AttributeList::AT_SysVABI: case AttributeList::AT_Pcs: case AttributeList::AT_IntelOclBicc: + case AttributeList::AT_PreserveMost: + case AttributeList::AT_PreserveAll: handleCallConvAttr(S, D, Attr); break; case AttributeList::AT_OpenCLKernel: handleSimpleAttribute<OpenCLKernelAttr>(S, D, Attr); break; - case AttributeList::AT_OpenCLImageAccess: - handleSimpleAttribute<OpenCLImageAccessAttr>(S, D, Attr); + case AttributeList::AT_OpenCLAccess: + handleOpenCLAccessAttr(S, D, Attr); + break; + case AttributeList::AT_OpenCLNoSVM: + handleOpenCLNoSVMAttr(S, D, Attr); + break; + case AttributeList::AT_SwiftContext: + handleParameterABIAttr(S, D, Attr, ParameterABI::SwiftContext); + break; + case AttributeList::AT_SwiftErrorResult: + handleParameterABIAttr(S, D, Attr, ParameterABI::SwiftErrorResult); + break; + case AttributeList::AT_SwiftIndirectResult: + handleParameterABIAttr(S, D, Attr, ParameterABI::SwiftIndirectResult); break; case AttributeList::AT_InternalLinkage: handleInternalLinkageAttr(S, D, Attr); break; + case AttributeList::AT_LTOVisibilityPublic: + handleSimpleAttribute<LTOVisibilityPublicAttr>(S, D, Attr); + break; // Microsoft attributes: + case AttributeList::AT_EmptyBases: + handleSimpleAttribute<EmptyBasesAttr>(S, D, Attr); + break; + case AttributeList::AT_LayoutVersion: + handleLayoutVersion(S, D, Attr); + break; case AttributeList::AT_MSNoVTable: handleSimpleAttribute<MSNoVTableAttr>(S, D, Attr); break; @@ -5361,6 +5800,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleDeclspecThreadAttr(S, D, Attr); break; + case AttributeList::AT_AbiTag: + handleAbiTagAttr(S, D, Attr); + break; + // Thread safety attributes: case AttributeList::AT_AssertExclusiveLock: handleAssertExclusiveLockAttr(S, D, Attr); @@ -5466,6 +5909,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_TypeTagForDatatype: handleTypeTagForDatatypeAttr(S, D, Attr); break; + case AttributeList::AT_RenderScriptKernel: + handleSimpleAttribute<RenderScriptKernelAttr>(S, D, Attr); + break; + // XRay attributes. + case AttributeList::AT_XRayInstrument: + handleSimpleAttribute<XRayInstrumentAttr>(S, D, Attr); + break; } } @@ -5744,7 +6194,6 @@ static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag, diag.Triggered = true; } - static bool isDeclDeprecated(Decl *D) { do { if (D->isDeprecated()) @@ -5769,6 +6218,34 @@ static bool isDeclUnavailable(Decl *D) { return false; } +static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context, + const Decl *D) { + // Check each AvailabilityAttr to find the one for this platform. + for (const auto *A : D->attrs()) { + if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) { + // FIXME: this is copied from CheckAvailability. We should try to + // de-duplicate. + + // Check if this is an App Extension "platform", and if so chop off + // the suffix for matching with the actual platform. + StringRef ActualPlatform = Avail->getPlatform()->getName(); + StringRef RealizedPlatform = ActualPlatform; + if (Context.getLangOpts().AppExt) { + size_t suffix = RealizedPlatform.rfind("_app_extension"); + if (suffix != StringRef::npos) + RealizedPlatform = RealizedPlatform.slice(0, suffix); + } + + StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); + + // Match the platform name. + if (RealizedPlatform == TargetPlatform) + return Avail; + } + } + return nullptr; +} + static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, Decl *Ctx, const NamedDecl *D, StringRef Message, SourceLocation Loc, @@ -5850,7 +6327,6 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, } } } - break; case Sema::AD_Partial: @@ -5862,23 +6338,61 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, break; } + CharSourceRange UseRange; + StringRef Replacement; + if (K == Sema::AD_Deprecation) { + if (auto attr = D->getAttr<DeprecatedAttr>()) + Replacement = attr->getReplacement(); + if (auto attr = getAttrForPlatform(S.Context, D)) + Replacement = attr->getReplacement(); + + if (!Replacement.empty()) + UseRange = + CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc)); + } + if (!Message.empty()) { - S.Diag(Loc, diag_message) << D << Message; + S.Diag(Loc, diag_message) << D << Message + << (UseRange.isValid() ? + FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else if (!UnknownObjCClass) { - S.Diag(Loc, diag) << D; + S.Diag(Loc, diag) << D + << (UseRange.isValid() ? + FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else { - S.Diag(Loc, diag_fwdclass_message) << D; + S.Diag(Loc, diag_fwdclass_message) << D + << (UseRange.isValid() ? + FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); } - S.Diag(D->getLocation(), diag_available_here) - << D << available_here_select_kind; + // The declaration can have multiple availability attributes, we are looking + // at one of them. + const AvailabilityAttr *A = getAttrForPlatform(S.Context, D); + if (A && A->isInherited()) { + for (const Decl *Redecl = D->getMostRecentDecl(); Redecl; + Redecl = Redecl->getPreviousDecl()) { + const AvailabilityAttr *AForRedecl = getAttrForPlatform(S.Context, + Redecl); + if (AForRedecl && !AForRedecl->isInherited()) { + // If D is a declaration with inherited attributes, the note should + // point to the declaration with actual attributes. + S.Diag(Redecl->getLocation(), diag_available_here) << D + << available_here_select_kind; + break; + } + } + } + else + S.Diag(D->getLocation(), diag_available_here) + << D << available_here_select_kind; + if (K == Sema::AD_Partial) S.Diag(Loc, diag::note_partial_availability_silence) << D; } |