diff options
Diffstat (limited to 'clang/lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 1060 |
1 files changed, 970 insertions, 90 deletions
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 1a0594512a60..30d08b3d4ac0 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -21,7 +21,9 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/Mangle.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/Type.h" #include "clang/Basic/CharInfo.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" @@ -30,12 +32,16 @@ #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/ParsedAttr.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/IR/Assumptions.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace sema; @@ -240,9 +246,9 @@ template <typename AttrInfo> static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr, uint32_t &Val, unsigned Idx = UINT_MAX, bool StrictlyUnsigned = false) { - llvm::APSInt I(32); + Optional<llvm::APSInt> I = llvm::APSInt(32); if (Expr->isTypeDependent() || Expr->isValueDependent() || - !Expr->isIntegerConstantExpr(I, S.Context)) { + !(I = Expr->getIntegerConstantExpr(S.Context))) { if (Idx != UINT_MAX) S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) << &AI << Idx << AANT_ArgumentIntegerConstant @@ -253,19 +259,19 @@ static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr, return false; } - if (!I.isIntN(32)) { + if (!I->isIntN(32)) { S.Diag(Expr->getExprLoc(), diag::err_ice_too_large) - << I.toString(10, false) << 32 << /* Unsigned */ 1; + << I->toString(10, false) << 32 << /* Unsigned */ 1; return false; } - if (StrictlyUnsigned && I.isSigned() && I.isNegative()) { + if (StrictlyUnsigned && I->isSigned() && I->isNegative()) { S.Diag(getAttrLoc(AI), diag::err_attribute_requires_positive_integer) << &AI << /*non-negative*/ 1; return false; } - Val = (uint32_t)I.getZExtValue(); + Val = (uint32_t)I->getZExtValue(); return true; } @@ -332,16 +338,16 @@ static bool checkFunctionOrMethodParameterIndex( unsigned NumParams = (HP ? getFunctionOrMethodNumParams(D) : 0) + HasImplicitThisParam; - llvm::APSInt IdxInt; + Optional<llvm::APSInt> IdxInt; if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || - !IdxExpr->isIntegerConstantExpr(IdxInt, S.Context)) { + !(IdxInt = IdxExpr->getIntegerConstantExpr(S.Context))) { S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) << &AI << AttrArgNum << AANT_ArgumentIntegerConstant << IdxExpr->getSourceRange(); return false; } - unsigned IdxSource = IdxInt.getLimitedValue(UINT_MAX); + unsigned IdxSource = IdxInt->getLimitedValue(UINT_MAX); if (IdxSource < 1 || (!IV && IdxSource > NumParams)) { S.Diag(getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds) << &AI << AttrArgNum << IdxExpr->getSourceRange(); @@ -1376,6 +1382,43 @@ static void handlePackedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL; } +static void handlePreferredName(Sema &S, Decl *D, const ParsedAttr &AL) { + auto *RD = cast<CXXRecordDecl>(D); + ClassTemplateDecl *CTD = RD->getDescribedClassTemplate(); + assert(CTD && "attribute does not appertain to this declaration"); + + ParsedType PT = AL.getTypeArg(); + TypeSourceInfo *TSI = nullptr; + QualType T = S.GetTypeFromParser(PT, &TSI); + if (!TSI) + TSI = S.Context.getTrivialTypeSourceInfo(T, AL.getLoc()); + + if (!T.hasQualifiers() && T->isTypedefNameType()) { + // Find the template name, if this type names a template specialization. + const TemplateDecl *Template = nullptr; + if (const auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>( + T->getAsCXXRecordDecl())) { + Template = CTSD->getSpecializedTemplate(); + } else if (const auto *TST = T->getAs<TemplateSpecializationType>()) { + while (TST && TST->isTypeAlias()) + TST = TST->getAliasedType()->getAs<TemplateSpecializationType>(); + if (TST) + Template = TST->getTemplateName().getAsTemplateDecl(); + } + + if (Template && declaresSameEntity(Template, CTD)) { + D->addAttr(::new (S.Context) PreferredNameAttr(S.Context, AL, TSI)); + return; + } + } + + S.Diag(AL.getLoc(), diag::err_attribute_preferred_name_arg_invalid) + << T << CTD; + if (const auto *TT = T->getAs<TypedefType>()) + S.Diag(TT->getDecl()->getLocation(), diag::note_entity_declared_at) + << TT->getDecl(); +} + static bool checkIBOutletCommon(Sema &S, Decl *D, const ParsedAttr &AL) { // The IBOutlet/IBOutletCollection attributes only apply to instance // variables or properties of Objective-C classes. The outlet must also @@ -1605,8 +1648,8 @@ void Sema::AddAssumeAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, } if (!E->isValueDependent()) { - llvm::APSInt I(64); - if (!E->isIntegerConstantExpr(I, Context)) { + Optional<llvm::APSInt> I = llvm::APSInt(64); + if (!(I = E->getIntegerConstantExpr(Context))) { if (OE) Diag(AttrLoc, diag::err_attribute_argument_n_type) << &TmpAttr << 1 << AANT_ArgumentIntegerConstant @@ -1618,27 +1661,22 @@ void Sema::AddAssumeAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, return; } - if (!I.isPowerOf2()) { + if (!I->isPowerOf2()) { Diag(AttrLoc, diag::err_alignment_not_power_of_two) << E->getSourceRange(); return; } - if (I > Sema::MaximumAlignment) + if (*I > Sema::MaximumAlignment) Diag(CI.getLoc(), diag::warn_assume_aligned_too_great) << CI.getRange() << Sema::MaximumAlignment; } - if (OE) { - if (!OE->isValueDependent()) { - llvm::APSInt I(64); - if (!OE->isIntegerConstantExpr(I, Context)) { - Diag(AttrLoc, diag::err_attribute_argument_n_type) - << &TmpAttr << 2 << AANT_ArgumentIntegerConstant - << OE->getSourceRange(); - return; - } - } + if (OE && !OE->isValueDependent() && !OE->isIntegerConstantExpr(Context)) { + Diag(AttrLoc, diag::err_attribute_argument_n_type) + << &TmpAttr << 2 << AANT_ArgumentIntegerConstant + << OE->getSourceRange(); + return; } D->addAttr(::new (Context) AssumeAlignedAttr(Context, CI, E, OE)); @@ -1676,6 +1714,42 @@ void Sema::AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI, D->addAttr(::new (Context) AllocAlignAttr(Context, CI, Idx)); } +/// Check if \p AssumptionStr is a known assumption and warn if not. +static void checkAssumptionAttr(Sema &S, SourceLocation Loc, + StringRef AssumptionStr) { + if (llvm::KnownAssumptionStrings.count(AssumptionStr)) + return; + + unsigned BestEditDistance = 3; + StringRef Suggestion; + for (const auto &KnownAssumptionIt : llvm::KnownAssumptionStrings) { + unsigned EditDistance = + AssumptionStr.edit_distance(KnownAssumptionIt.getKey()); + if (EditDistance < BestEditDistance) { + Suggestion = KnownAssumptionIt.getKey(); + BestEditDistance = EditDistance; + } + } + + if (!Suggestion.empty()) + S.Diag(Loc, diag::warn_assume_attribute_string_unknown_suggested) + << AssumptionStr << Suggestion; + else + S.Diag(Loc, diag::warn_assume_attribute_string_unknown) << AssumptionStr; +} + +static void handleAssumumptionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // Handle the case where the attribute has a text message. + StringRef Str; + SourceLocation AttrStrLoc; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &AttrStrLoc)) + return; + + checkAssumptionAttr(S, AttrStrLoc, Str); + + D->addAttr(::new (S.Context) AssumptionAttr(S.Context, AL, Str)); +} + /// Normalize the attribute, __foo__ becomes foo. /// Returns true if normalization was applied. static bool normalizeName(StringRef &AttrName) { @@ -2056,7 +2130,8 @@ bool Sema::CheckAttrNoArgs(const ParsedAttr &Attrs) { bool Sema::CheckAttrTarget(const ParsedAttr &AL) { // Check whether the attribute is valid on the current target. if (!AL.existsInTarget(Context.getTargetInfo())) { - Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL; + Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) + << AL << AL.getRange(); AL.setInvalid(); return true; } @@ -2618,6 +2693,11 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL, D->addAttr(newAttr); } +static void handleObjCNonRuntimeProtocolAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + handleSimpleAttribute<ObjCNonRuntimeProtocolAttr>(S, D, AL); +} + static void handleObjCDirectAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // objc_direct cannot be set on methods declared in the context of a protocol if (isa<ObjCProtocolDecl>(D->getDeclContext())) { @@ -2729,36 +2809,36 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { unsigned sentinel = (unsigned)SentinelAttr::DefaultSentinel; if (AL.getNumArgs() > 0) { Expr *E = AL.getArgAsExpr(0); - llvm::APSInt Idx(32); + Optional<llvm::APSInt> Idx = llvm::APSInt(32); if (E->isTypeDependent() || E->isValueDependent() || - !E->isIntegerConstantExpr(Idx, S.Context)) { + !(Idx = E->getIntegerConstantExpr(S.Context))) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) << AL << 1 << AANT_ArgumentIntegerConstant << E->getSourceRange(); return; } - if (Idx.isSigned() && Idx.isNegative()) { + if (Idx->isSigned() && Idx->isNegative()) { S.Diag(AL.getLoc(), diag::err_attribute_sentinel_less_than_zero) << E->getSourceRange(); return; } - sentinel = Idx.getZExtValue(); + sentinel = Idx->getZExtValue(); } unsigned nullPos = (unsigned)SentinelAttr::DefaultNullPos; if (AL.getNumArgs() > 1) { Expr *E = AL.getArgAsExpr(1); - llvm::APSInt Idx(32); + Optional<llvm::APSInt> Idx = llvm::APSInt(32); if (E->isTypeDependent() || E->isValueDependent() || - !E->isIntegerConstantExpr(Idx, S.Context)) { + !(Idx = E->getIntegerConstantExpr(S.Context))) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) << AL << 2 << AANT_ArgumentIntegerConstant << E->getSourceRange(); return; } - nullPos = Idx.getZExtValue(); + nullPos = Idx->getZExtValue(); - if ((Idx.isSigned() && Idx.isNegative()) || nullPos > 1) { + if ((Idx->isSigned() && Idx->isNegative()) || nullPos > 1) { // FIXME: This error message could be improved, it would be nice // to say what the bounds actually are. S.Diag(AL.getLoc(), diag::err_attribute_sentinel_not_zero_or_one) @@ -3001,8 +3081,14 @@ static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } SectionAttr *NewAttr = S.mergeSectionAttr(D, AL, Str); - if (NewAttr) + if (NewAttr) { D->addAttr(NewAttr); + if (isa<FunctionDecl, FunctionTemplateDecl, ObjCMethodDecl, + ObjCPropertyDecl>(D)) + S.UnifySection(NewAttr->getName(), + ASTContext::PSF_Execute | ASTContext::PSF_Read, + cast<NamedDecl>(D)); + } } // This is used for `__declspec(code_seg("segname"))` on a decl. @@ -3063,23 +3149,36 @@ static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Check for things we'd like to warn about. Multiversioning issues are // handled later in the process, once we know how many exist. bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { - enum FirstParam { Unsupported, Duplicate }; - enum SecondParam { None, Architecture }; - for (auto Str : {"tune=", "fpmath="}) - if (AttrStr.find(Str) != StringRef::npos) - return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << Str; + enum FirstParam { Unsupported, Duplicate, Unknown }; + enum SecondParam { None, Architecture, Tune }; + if (AttrStr.find("fpmath=") != StringRef::npos) + return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << "fpmath="; + + // Diagnose use of tune if target doesn't support it. + if (!Context.getTargetInfo().supportsTargetAttributeTune() && + AttrStr.find("tune=") != StringRef::npos) + return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << "tune="; ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr); if (!ParsedAttrs.Architecture.empty() && !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Architecture)) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unsupported << Architecture << ParsedAttrs.Architecture; + << Unknown << Architecture << ParsedAttrs.Architecture; + + if (!ParsedAttrs.Tune.empty() && + !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Tune)) + return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) + << Unknown << Tune << ParsedAttrs.Tune; if (ParsedAttrs.DuplicateArchitecture) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Duplicate << None << "arch="; + if (ParsedAttrs.DuplicateTune) + return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) + << Duplicate << None << "tune="; for (const auto &Feature : ParsedAttrs.Features) { auto CurFeature = StringRef(Feature).drop_front(); // remove + or -. @@ -3301,7 +3400,11 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - if (prioritynum < 101 || prioritynum > 65535) { + // Only perform the priority check if the attribute is outside of a system + // header. Values <= 100 are reserved for the implementation, and libc++ + // benefits from being able to specify values in that range. + if ((prioritynum < 101 || prioritynum > 65535) && + !S.getSourceManager().isInSystemHeader(AL.getLoc())) { S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_range) << E->getSourceRange() << AL << 101 << 65535; AL.setInvalid(); @@ -3590,6 +3693,26 @@ static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.Context, AL, EncodingIndices.data(), EncodingIndices.size())); } +static bool isFunctionLike(const Type &T) { + // Check for explicit function types. + // 'called_once' is only supported in Objective-C and it has + // function pointers and block pointers. + return T.isFunctionPointerType() || T.isBlockPointerType(); +} + +/// Handle 'called_once' attribute. +static void handleCalledOnceAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // 'called_once' only applies to parameters representing functions. + QualType T = cast<ParmVarDecl>(D)->getType(); + + if (!isFunctionLike(*T)) { + S.Diag(AL.getLoc(), diag::err_called_once_attribute_wrong_type); + return; + } + + D->addAttr(::new (S.Context) CalledOnceAttr(S.Context, AL)); +} + static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Try to find the underlying union declaration. RecordDecl *RD = nullptr; @@ -3645,15 +3768,15 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.Context.getTypeAlign(FieldType) > FirstAlign) { // Warn if we drop the attribute. bool isSize = S.Context.getTypeSize(FieldType) != FirstSize; - unsigned FieldBits = isSize? S.Context.getTypeSize(FieldType) - : S.Context.getTypeAlign(FieldType); + unsigned FieldBits = isSize ? S.Context.getTypeSize(FieldType) + : S.Context.getTypeAlign(FieldType); S.Diag(Field->getLocation(), - diag::warn_transparent_union_attribute_field_size_align) - << isSize << Field->getDeclName() << FieldBits; - unsigned FirstBits = isSize? FirstSize : FirstAlign; + diag::warn_transparent_union_attribute_field_size_align) + << isSize << *Field << FieldBits; + unsigned FirstBits = isSize ? FirstSize : FirstAlign; S.Diag(FirstField->getLocation(), diag::note_transparent_union_first_field_size_align) - << isSize << FirstBits; + << isSize << FirstBits; return; } } @@ -3661,20 +3784,68 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { RD->addAttr(::new (S.Context) TransparentUnionAttr(S.Context, AL)); } +void Sema::AddAnnotationAttr(Decl *D, const AttributeCommonInfo &CI, + StringRef Str, MutableArrayRef<Expr *> Args) { + auto *Attr = AnnotateAttr::Create(Context, Str, Args.data(), Args.size(), CI); + llvm::SmallVector<PartialDiagnosticAt, 8> Notes; + for (unsigned Idx = 0; Idx < Attr->args_size(); Idx++) { + Expr *&E = Attr->args_begin()[Idx]; + assert(E && "error are handled before"); + if (E->isValueDependent() || E->isTypeDependent()) + continue; + + if (E->getType()->isArrayType()) + E = ImpCastExprToType(E, Context.getPointerType(E->getType()), + clang::CK_ArrayToPointerDecay) + .get(); + if (E->getType()->isFunctionType()) + E = ImplicitCastExpr::Create(Context, + Context.getPointerType(E->getType()), + clang::CK_FunctionToPointerDecay, E, nullptr, + VK_RValue, FPOptionsOverride()); + if (E->isLValue()) + E = ImplicitCastExpr::Create(Context, E->getType().getNonReferenceType(), + clang::CK_LValueToRValue, E, nullptr, + VK_RValue, FPOptionsOverride()); + + Expr::EvalResult Eval; + Notes.clear(); + Eval.Diag = &Notes; + + bool Result = + E->EvaluateAsConstantExpr(Eval, Context); + + /// Result means the expression can be folded to a constant. + /// Note.empty() means the expression is a valid constant expression in the + /// current language mode. + if (!Result || !Notes.empty()) { + Diag(E->getBeginLoc(), diag::err_attribute_argument_n_type) + << CI << (Idx + 1) << AANT_ArgumentConstantExpr; + for (auto &Note : Notes) + Diag(Note.first, Note.second); + return; + } + assert(Eval.Val.hasValue()); + E = ConstantExpr::Create(Context, E, Eval.Val); + } + D->addAttr(Attr); +} + static void handleAnnotateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - // Make sure that there is a string literal as the annotation's single + // Make sure that there is a string literal as the annotation's first // argument. StringRef Str; if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; - // Don't duplicate annotations that are already set. - for (const auto *I : D->specific_attrs<AnnotateAttr>()) { - if (I->getAnnotation() == Str) - return; + llvm::SmallVector<Expr *, 4> Args; + Args.reserve(AL.getNumArgs() - 1); + for (unsigned Idx = 1; Idx < AL.getNumArgs(); Idx++) { + assert(!AL.isArgIdent(Idx)); + Args.push_back(AL.getArgAsExpr(Idx)); } - D->addAttr(::new (S.Context) AnnotateAttr(S.Context, AL, Str)); + S.AddAnnotationAttr(D, AL, Str, Args); } static void handleAlignValueAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -3702,10 +3873,8 @@ void Sema::AddAlignValueAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E) { if (!E->isValueDependent()) { llvm::APSInt Alignment; - ExprResult ICE - = VerifyIntegerConstantExpression(E, &Alignment, - diag::err_align_value_attribute_argument_not_int, - /*AllowFold*/ false); + ExprResult ICE = VerifyIntegerConstantExpression( + E, &Alignment, diag::err_align_value_attribute_argument_not_int); if (ICE.isInvalid()) return; @@ -3811,10 +3980,8 @@ void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, // FIXME: Cache the number on the AL object? llvm::APSInt Alignment; - ExprResult ICE - = VerifyIntegerConstantExpression(E, &Alignment, - diag::err_aligned_attribute_argument_not_int, - /*AllowFold*/ false); + ExprResult ICE = VerifyIntegerConstantExpression( + E, &Alignment, diag::err_aligned_attribute_argument_not_int); if (ICE.isInvalid()) return; @@ -4265,6 +4432,20 @@ NoSpeculativeLoadHardeningAttr *Sema::mergeNoSpeculativeLoadHardeningAttr( return ::new (Context) NoSpeculativeLoadHardeningAttr(Context, AL); } +SwiftNameAttr *Sema::mergeSwiftNameAttr(Decl *D, const SwiftNameAttr &SNA, + StringRef Name) { + if (const auto *PrevSNA = D->getAttr<SwiftNameAttr>()) { + if (PrevSNA->getName() != Name && !PrevSNA->isImplicit()) { + Diag(PrevSNA->getLocation(), diag::err_attributes_are_not_compatible) + << PrevSNA << &SNA; + Diag(SNA.getLoc(), diag::note_conflicting_attribute); + } + + D->dropAttr<SwiftNameAttr>(); + } + return ::new (Context) SwiftNameAttr(Context, SNA, Name); +} + OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, const AttributeCommonInfo &CI) { if (AlwaysInlineAttr *Inline = D->getAttr<AlwaysInlineAttr>()) { @@ -4312,18 +4493,20 @@ static void handleOptimizeNoneAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleConstantAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (checkAttrMutualExclusion<CUDASharedAttr>(S, D, AL)) + if (checkAttrMutualExclusion<CUDASharedAttr>(S, D, AL) || + checkAttrMutualExclusion<HIPManagedAttr>(S, D, AL)) return; const auto *VD = cast<VarDecl>(D); - if (!VD->hasGlobalStorage()) { - S.Diag(AL.getLoc(), diag::err_cuda_nonglobal_constant); + if (VD->hasLocalStorage()) { + S.Diag(AL.getLoc(), diag::err_cuda_nonstatic_constdev); return; } D->addAttr(::new (S.Context) CUDAConstantAttr(S.Context, AL)); } static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (checkAttrMutualExclusion<CUDAConstantAttr>(S, D, AL)) + if (checkAttrMutualExclusion<CUDAConstantAttr>(S, D, AL) || + checkAttrMutualExclusion<HIPManagedAttr>(S, D, AL)) return; const auto *VD = cast<VarDecl>(D); // extern __shared__ is only allowed on arrays with no length (e.g. @@ -4377,6 +4560,44 @@ static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(NoDebugAttr::CreateImplicit(S.Context)); } +static void handleDeviceAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (checkAttrMutualExclusion<CUDAGlobalAttr>(S, D, AL)) { + return; + } + + if (const auto *VD = dyn_cast<VarDecl>(D)) { + if (VD->hasLocalStorage()) { + S.Diag(AL.getLoc(), diag::err_cuda_nonstatic_constdev); + return; + } + } + + if (auto *A = D->getAttr<CUDADeviceAttr>()) { + if (!A->isImplicit()) + return; + D->dropAttr<CUDADeviceAttr>(); + } + D->addAttr(::new (S.Context) CUDADeviceAttr(S.Context, AL)); +} + +static void handleManagedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (checkAttrMutualExclusion<CUDAConstantAttr>(S, D, AL) || + checkAttrMutualExclusion<CUDASharedAttr>(S, D, AL)) { + return; + } + + if (const auto *VD = dyn_cast<VarDecl>(D)) { + if (VD->hasLocalStorage()) { + S.Diag(AL.getLoc(), diag::err_cuda_nonstatic_constdev); + return; + } + } + if (!D->hasAttr<HIPManagedAttr>()) + D->addAttr(::new (S.Context) HIPManagedAttr(S.Context, AL)); + if (!D->hasAttr<CUDADeviceAttr>()) + D->addAttr(CUDADeviceAttr::CreateImplicit(S.Context)); +} + static void handleGNUInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) { const auto *Fn = cast<FunctionDecl>(D); if (!Fn->isInlineSpecified()) { @@ -4833,19 +5054,19 @@ static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E, if (E->isValueDependent()) return E; - llvm::APSInt I(64); - if (!E->isIntegerConstantExpr(I, S.Context)) { + Optional<llvm::APSInt> I = llvm::APSInt(64); + if (!(I = E->getIntegerConstantExpr(S.Context))) { S.Diag(E->getExprLoc(), diag::err_attribute_argument_n_type) << &AL << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange(); 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; + if (!I->isIntN(32)) { + S.Diag(E->getExprLoc(), diag::err_ice_too_large) + << I->toString(10, false) << 32 << /* Unsigned */ 1; return nullptr; } - if (I < 0) + if (*I < 0) S.Diag(E->getExprLoc(), diag::warn_attribute_argument_n_negative) << &AL << Idx << E->getSourceRange(); @@ -5327,6 +5548,31 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(S.Context, Attrs)); } +static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &AL) { + auto *E = AL.getArgAsExpr(0); + auto Loc = E ? E->getBeginLoc() : AL.getLoc(); + + auto *DRE = dyn_cast<DeclRefExpr>(AL.getArgAsExpr(0)); + if (!DRE) { + S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; + return; + } + + auto *VD = dyn_cast<VarDecl>(DRE->getDecl()); + if (!VD) { + S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 1 << DRE->getDecl(); + return; + } + + if (!isNSStringType(VD->getType(), S.Context) && + !isCFStringType(VD->getType(), S.Context)) { + S.Diag(Loc, diag::err_nserrordomain_wrong_type) << VD; + return; + } + + D->addAttr(::new (S.Context) NSErrorDomainAttr(S.Context, AL, VD)); +} + static void handleObjCBridgeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr; @@ -5488,6 +5734,515 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, D->addAttr(::new (S.Context) ObjCPreciseLifetimeAttr(S.Context, AL)); } +static void handleSwiftAttrAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // Make sure that there is a string literal as the annotation's single + // argument. + StringRef Str; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) + return; + + D->addAttr(::new (S.Context) SwiftAttrAttr(S.Context, AL, Str)); +} + +static void handleSwiftBridge(Sema &S, Decl *D, const ParsedAttr &AL) { + // Make sure that there is a string literal as the annotation's single + // argument. + StringRef BT; + if (!S.checkStringLiteralArgumentAttr(AL, 0, BT)) + return; + + // Don't duplicate annotations that are already set. + if (D->hasAttr<SwiftBridgeAttr>()) { + S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; + return; + } + + D->addAttr(::new (S.Context) SwiftBridgeAttr(S.Context, AL, BT)); +} + +static bool isErrorParameter(Sema &S, QualType QT) { + const auto *PT = QT->getAs<PointerType>(); + if (!PT) + return false; + + QualType Pointee = PT->getPointeeType(); + + // Check for NSError**. + if (const auto *OPT = Pointee->getAs<ObjCObjectPointerType>()) + if (const auto *ID = OPT->getInterfaceDecl()) + if (ID->getIdentifier() == S.getNSErrorIdent()) + return true; + + // Check for CFError**. + if (const auto *PT = Pointee->getAs<PointerType>()) + if (const auto *RT = PT->getPointeeType()->getAs<RecordType>()) + if (S.isCFError(RT->getDecl())) + return true; + + return false; +} + +static void handleSwiftError(Sema &S, Decl *D, const ParsedAttr &AL) { + auto hasErrorParameter = [](Sema &S, Decl *D, const ParsedAttr &AL) -> bool { + for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); I != E; ++I) { + if (isErrorParameter(S, getFunctionOrMethodParamType(D, I))) + return true; + } + + S.Diag(AL.getLoc(), diag::err_attr_swift_error_no_error_parameter) + << AL << isa<ObjCMethodDecl>(D); + return false; + }; + + auto hasPointerResult = [](Sema &S, Decl *D, const ParsedAttr &AL) -> bool { + // - C, ObjC, and block pointers are definitely okay. + // - References are definitely not okay. + // - nullptr_t is weird, but acceptable. + QualType RT = getFunctionOrMethodResultType(D); + if (RT->hasPointerRepresentation() && !RT->isReferenceType()) + return true; + + S.Diag(AL.getLoc(), diag::err_attr_swift_error_return_type) + << AL << AL.getArgAsIdent(0)->Ident->getName() << isa<ObjCMethodDecl>(D) + << /*pointer*/ 1; + return false; + }; + + auto hasIntegerResult = [](Sema &S, Decl *D, const ParsedAttr &AL) -> bool { + QualType RT = getFunctionOrMethodResultType(D); + if (RT->isIntegralType(S.Context)) + return true; + + S.Diag(AL.getLoc(), diag::err_attr_swift_error_return_type) + << AL << AL.getArgAsIdent(0)->Ident->getName() << isa<ObjCMethodDecl>(D) + << /*integral*/ 0; + return false; + }; + + if (D->isInvalidDecl()) + return; + + IdentifierLoc *Loc = AL.getArgAsIdent(0); + SwiftErrorAttr::ConventionKind Convention; + if (!SwiftErrorAttr::ConvertStrToConventionKind(Loc->Ident->getName(), + Convention)) { + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL << Loc->Ident; + return; + } + + switch (Convention) { + case SwiftErrorAttr::None: + // No additional validation required. + break; + + case SwiftErrorAttr::NonNullError: + if (!hasErrorParameter(S, D, AL)) + return; + break; + + case SwiftErrorAttr::NullResult: + if (!hasErrorParameter(S, D, AL) || !hasPointerResult(S, D, AL)) + return; + break; + + case SwiftErrorAttr::NonZeroResult: + case SwiftErrorAttr::ZeroResult: + if (!hasErrorParameter(S, D, AL) || !hasIntegerResult(S, D, AL)) + return; + break; + } + + D->addAttr(::new (S.Context) SwiftErrorAttr(S.Context, AL, Convention)); +} + +// For a function, this will validate a compound Swift name, e.g. +// <code>init(foo:bar:baz:)</code> or <code>controllerForName(_:)</code>, and +// the function will output the number of parameter names, and whether this is a +// single-arg initializer. +// +// For a type, enum constant, property, or variable declaration, this will +// validate either a simple identifier, or a qualified +// <code>context.identifier</code> name. +static bool +validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, SourceLocation Loc, + StringRef Name, unsigned &SwiftParamCount, + bool &IsSingleParamInit) { + SwiftParamCount = 0; + IsSingleParamInit = false; + + // Check whether this will be mapped to a getter or setter of a property. + bool IsGetter = false, IsSetter = false; + if (Name.startswith("getter:")) { + IsGetter = true; + Name = Name.substr(7); + } else if (Name.startswith("setter:")) { + IsSetter = true; + Name = Name.substr(7); + } + + if (Name.back() != ')') { + S.Diag(Loc, diag::warn_attr_swift_name_function) << AL; + return false; + } + + bool IsMember = false; + StringRef ContextName, BaseName, Parameters; + + std::tie(BaseName, Parameters) = Name.split('('); + + // Split at the first '.', if it exists, which separates the context name + // from the base name. + std::tie(ContextName, BaseName) = BaseName.split('.'); + if (BaseName.empty()) { + BaseName = ContextName; + ContextName = StringRef(); + } else if (ContextName.empty() || !isValidIdentifier(ContextName)) { + S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) + << AL << /*context*/ 1; + return false; + } else { + IsMember = true; + } + + if (!isValidIdentifier(BaseName) || BaseName == "_") { + S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) + << AL << /*basename*/ 0; + return false; + } + + bool IsSubscript = BaseName == "subscript"; + // A subscript accessor must be a getter or setter. + if (IsSubscript && !IsGetter && !IsSetter) { + S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter) + << AL << /* getter or setter */ 0; + return false; + } + + if (Parameters.empty()) { + S.Diag(Loc, diag::warn_attr_swift_name_missing_parameters) << AL; + return false; + } + + assert(Parameters.back() == ')' && "expected ')'"); + Parameters = Parameters.drop_back(); // ')' + + if (Parameters.empty()) { + // Setters and subscripts must have at least one parameter. + if (IsSubscript) { + S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter) + << AL << /* have at least one parameter */1; + return false; + } + + if (IsSetter) { + S.Diag(Loc, diag::warn_attr_swift_name_setter_parameters) << AL; + return false; + } + + return true; + } + + if (Parameters.back() != ':') { + S.Diag(Loc, diag::warn_attr_swift_name_function) << AL; + return false; + } + + StringRef CurrentParam; + llvm::Optional<unsigned> SelfLocation; + unsigned NewValueCount = 0; + llvm::Optional<unsigned> NewValueLocation; + do { + std::tie(CurrentParam, Parameters) = Parameters.split(':'); + + if (!isValidIdentifier(CurrentParam)) { + S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) + << AL << /*parameter*/2; + return false; + } + + if (IsMember && CurrentParam == "self") { + // "self" indicates the "self" argument for a member. + + // More than one "self"? + if (SelfLocation) { + S.Diag(Loc, diag::warn_attr_swift_name_multiple_selfs) << AL; + return false; + } + + // The "self" location is the current parameter. + SelfLocation = SwiftParamCount; + } else if (CurrentParam == "newValue") { + // "newValue" indicates the "newValue" argument for a setter. + + // There should only be one 'newValue', but it's only significant for + // subscript accessors, so don't error right away. + ++NewValueCount; + + NewValueLocation = SwiftParamCount; + } + + ++SwiftParamCount; + } while (!Parameters.empty()); + + // Only instance subscripts are currently supported. + if (IsSubscript && !SelfLocation) { + S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter) + << AL << /*have a 'self:' parameter*/2; + return false; + } + + IsSingleParamInit = + SwiftParamCount == 1 && BaseName == "init" && CurrentParam != "_"; + + // Check the number of parameters for a getter/setter. + if (IsGetter || IsSetter) { + // Setters have one parameter for the new value. + unsigned NumExpectedParams = IsGetter ? 0 : 1; + unsigned ParamDiag = + IsGetter ? diag::warn_attr_swift_name_getter_parameters + : diag::warn_attr_swift_name_setter_parameters; + + // Instance methods have one parameter for "self". + if (SelfLocation) + ++NumExpectedParams; + + // Subscripts may have additional parameters beyond the expected params for + // the index. + if (IsSubscript) { + if (SwiftParamCount < NumExpectedParams) { + S.Diag(Loc, ParamDiag) << AL; + return false; + } + + // A subscript setter must explicitly label its newValue parameter to + // distinguish it from index parameters. + if (IsSetter) { + if (!NewValueLocation) { + S.Diag(Loc, diag::warn_attr_swift_name_subscript_setter_no_newValue) + << AL; + return false; + } + if (NewValueCount > 1) { + S.Diag(Loc, diag::warn_attr_swift_name_subscript_setter_multiple_newValues) + << AL; + return false; + } + } else { + // Subscript getters should have no 'newValue:' parameter. + if (NewValueLocation) { + S.Diag(Loc, diag::warn_attr_swift_name_subscript_getter_newValue) + << AL; + return false; + } + } + } else { + // Property accessors must have exactly the number of expected params. + if (SwiftParamCount != NumExpectedParams) { + S.Diag(Loc, ParamDiag) << AL; + return false; + } + } + } + + return true; +} + +bool Sema::DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc, + const ParsedAttr &AL, bool IsAsync) { + if (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(D)) { + ArrayRef<ParmVarDecl*> Params; + unsigned ParamCount; + + if (const auto *Method = dyn_cast<ObjCMethodDecl>(D)) { + ParamCount = Method->getSelector().getNumArgs(); + Params = Method->parameters().slice(0, ParamCount); + } else { + const auto *F = cast<FunctionDecl>(D); + + ParamCount = F->getNumParams(); + Params = F->parameters(); + + if (!F->hasWrittenPrototype()) { + Diag(Loc, diag::warn_attribute_wrong_decl_type) << AL + << ExpectedFunctionWithProtoType; + return false; + } + } + + // The async name drops the last callback parameter. + if (IsAsync) { + if (ParamCount == 0) { + Diag(Loc, diag::warn_attr_swift_name_decl_missing_params) + << AL << isa<ObjCMethodDecl>(D); + return false; + } + ParamCount -= 1; + } + + unsigned SwiftParamCount; + bool IsSingleParamInit; + if (!validateSwiftFunctionName(*this, AL, Loc, Name, + SwiftParamCount, IsSingleParamInit)) + return false; + + bool ParamCountValid; + if (SwiftParamCount == ParamCount) { + ParamCountValid = true; + } else if (SwiftParamCount > ParamCount) { + ParamCountValid = IsSingleParamInit && ParamCount == 0; + } else { + // We have fewer Swift parameters than Objective-C parameters, but that + // might be because we've transformed some of them. Check for potential + // "out" parameters and err on the side of not warning. + unsigned MaybeOutParamCount = + std::count_if(Params.begin(), Params.end(), + [](const ParmVarDecl *Param) -> bool { + QualType ParamTy = Param->getType(); + if (ParamTy->isReferenceType() || ParamTy->isPointerType()) + return !ParamTy->getPointeeType().isConstQualified(); + return false; + }); + + ParamCountValid = SwiftParamCount + MaybeOutParamCount >= ParamCount; + } + + if (!ParamCountValid) { + Diag(Loc, diag::warn_attr_swift_name_num_params) + << (SwiftParamCount > ParamCount) << AL << ParamCount + << SwiftParamCount; + return false; + } + } else if ((isa<EnumConstantDecl>(D) || isa<ObjCProtocolDecl>(D) || + isa<ObjCInterfaceDecl>(D) || isa<ObjCPropertyDecl>(D) || + isa<VarDecl>(D) || isa<TypedefNameDecl>(D) || isa<TagDecl>(D) || + isa<IndirectFieldDecl>(D) || isa<FieldDecl>(D)) && + !IsAsync) { + StringRef ContextName, BaseName; + + std::tie(ContextName, BaseName) = Name.split('.'); + if (BaseName.empty()) { + BaseName = ContextName; + ContextName = StringRef(); + } else if (!isValidIdentifier(ContextName)) { + Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL + << /*context*/1; + return false; + } + + if (!isValidIdentifier(BaseName)) { + Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL + << /*basename*/0; + return false; + } + } else { + Diag(Loc, diag::warn_attr_swift_name_decl_kind) << AL; + return false; + } + return true; +} + +static void handleSwiftName(Sema &S, Decl *D, const ParsedAttr &AL) { + StringRef Name; + SourceLocation Loc; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Name, &Loc)) + return; + + if (!S.DiagnoseSwiftName(D, Name, Loc, AL, /*IsAsync=*/false)) + return; + + D->addAttr(::new (S.Context) SwiftNameAttr(S.Context, AL, Name)); +} + +static void handleSwiftAsyncName(Sema &S, Decl *D, const ParsedAttr &AL) { + StringRef Name; + SourceLocation Loc; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Name, &Loc)) + return; + + if (!S.DiagnoseSwiftName(D, Name, Loc, AL, /*IsAsync=*/true)) + return; + + D->addAttr(::new (S.Context) SwiftAsyncNameAttr(S.Context, AL, Name)); +} + +static void handleSwiftNewType(Sema &S, Decl *D, const ParsedAttr &AL) { + // Make sure that there is an identifier as the annotation's single argument. + if (!checkAttributeNumArgs(S, AL, 1)) + return; + + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; + return; + } + + SwiftNewTypeAttr::NewtypeKind Kind; + IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; + if (!SwiftNewTypeAttr::ConvertStrToNewtypeKind(II->getName(), Kind)) { + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II; + return; + } + + if (!isa<TypedefNameDecl>(D)) { + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str) + << AL << "typedefs"; + return; + } + + D->addAttr(::new (S.Context) SwiftNewTypeAttr(S.Context, AL, Kind)); +} + +static void handleSwiftAsyncAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL << 1 << AANT_ArgumentIdentifier; + return; + } + + SwiftAsyncAttr::Kind Kind; + IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; + if (!SwiftAsyncAttr::ConvertStrToKind(II->getName(), Kind)) { + S.Diag(AL.getLoc(), diag::err_swift_async_no_access) << AL << II; + return; + } + + ParamIdx Idx; + if (Kind == SwiftAsyncAttr::None) { + // If this is 'none', then there shouldn't be any additional arguments. + if (!checkAttributeNumArgs(S, AL, 1)) + return; + } else { + // Non-none swift_async requires a completion handler index argument. + if (!checkAttributeNumArgs(S, AL, 2)) + return; + + Expr *HandlerIdx = AL.getArgAsExpr(1); + if (!checkFunctionOrMethodParameterIndex(S, D, AL, 2, HandlerIdx, Idx)) + return; + + const ParmVarDecl *CompletionBlock = + getFunctionOrMethodParam(D, Idx.getASTIndex()); + QualType CompletionBlockType = CompletionBlock->getType(); + if (!CompletionBlockType->isBlockPointerType()) { + S.Diag(CompletionBlock->getLocation(), + diag::err_swift_async_bad_block_type) + << CompletionBlock->getType(); + return; + } + QualType BlockTy = + CompletionBlockType->getAs<BlockPointerType>()->getPointeeType(); + if (!BlockTy->getAs<FunctionType>()->getReturnType()->isVoidType()) { + S.Diag(CompletionBlock->getLocation(), + diag::err_swift_async_bad_block_type) + << CompletionBlock->getType(); + return; + } + } + + D->addAttr(::new (S.Context) SwiftAsyncAttr(S.Context, AL, Kind, Idx)); +} + //===----------------------------------------------------------------------===// // Microsoft specific attribute handlers. //===----------------------------------------------------------------------===// @@ -5686,18 +6441,18 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0)); - llvm::APSInt NumParams(32); - if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { + Optional<llvm::APSInt> NumParams = llvm::APSInt(32); + if (!(NumParams = NumParamsExpr->getIntegerConstantExpr(S.Context))) { S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << AL << AANT_ArgumentIntegerConstant << NumParamsExpr->getSourceRange(); return; } // The argument should be in range 0..63. - unsigned Num = NumParams.getLimitedValue(255); + unsigned Num = NumParams->getLimitedValue(255); if (Num > 63) { S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) - << AL << (int)NumParams.getSExtValue() + << AL << (int)NumParams->getSExtValue() << NumParamsExpr->getSourceRange(); return; } @@ -6246,14 +7001,14 @@ DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) { if (isa<ClassTemplatePartialSpecializationDecl>(D) && - S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { + (S.Context.getTargetInfo().shouldDLLImportComdatSymbols())) { S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored) << A; return; } if (const auto *FD = dyn_cast<FunctionDecl>(D)) { if (FD->isInlined() && A.getKind() == ParsedAttr::AT_DLLImport && - !S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { + !(S.Context.getTargetInfo().shouldDLLImportComdatSymbols())) { // MinGW doesn't allow dllimport on inline functions. S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored_on_inline) << A; @@ -6262,7 +7017,7 @@ static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) { } if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { - if (S.Context.getTargetInfo().getCXXABI().isMicrosoft() && + if ((S.Context.getTargetInfo().shouldDLLImportComdatSymbols()) && MD->getParent()->isLambda()) { S.Diag(A.getRange().getBegin(), diag::err_attribute_dll_lambda) << A; return; @@ -6788,6 +7543,75 @@ static void handleCFGuardAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(::new (S.Context) CFGuardAttr(S.Context, AL, Arg)); } + +template <typename AttrTy> +static const AttrTy *findEnforceTCBAttrByName(Decl *D, StringRef Name) { + auto Attrs = D->specific_attrs<AttrTy>(); + auto I = llvm::find_if(Attrs, + [Name](const AttrTy *A) { + return A->getTCBName() == Name; + }); + return I == Attrs.end() ? nullptr : *I; +} + +template <typename AttrTy, typename ConflictingAttrTy> +static void handleEnforceTCBAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + StringRef Argument; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Argument)) + return; + + // A function cannot be have both regular and leaf membership in the same TCB. + if (const ConflictingAttrTy *ConflictingAttr = + findEnforceTCBAttrByName<ConflictingAttrTy>(D, Argument)) { + // We could attach a note to the other attribute but in this case + // there's no need given how the two are very close to each other. + S.Diag(AL.getLoc(), diag::err_tcb_conflicting_attributes) + << AL.getAttrName()->getName() << ConflictingAttr->getAttrName()->getName() + << Argument; + + // Error recovery: drop the non-leaf attribute so that to suppress + // all future warnings caused by erroneous attributes. The leaf attribute + // needs to be kept because it can only suppresses warnings, not cause them. + D->dropAttr<EnforceTCBAttr>(); + return; + } + + D->addAttr(AttrTy::Create(S.Context, Argument, AL)); +} + +template <typename AttrTy, typename ConflictingAttrTy> +static AttrTy *mergeEnforceTCBAttrImpl(Sema &S, Decl *D, const AttrTy &AL) { + // Check if the new redeclaration has different leaf-ness in the same TCB. + StringRef TCBName = AL.getTCBName(); + if (const ConflictingAttrTy *ConflictingAttr = + findEnforceTCBAttrByName<ConflictingAttrTy>(D, TCBName)) { + S.Diag(ConflictingAttr->getLoc(), diag::err_tcb_conflicting_attributes) + << ConflictingAttr->getAttrName()->getName() + << AL.getAttrName()->getName() << TCBName; + + // Add a note so that the user could easily find the conflicting attribute. + S.Diag(AL.getLoc(), diag::note_conflicting_attribute); + + // More error recovery. + D->dropAttr<EnforceTCBAttr>(); + return nullptr; + } + + ASTContext &Context = S.getASTContext(); + return ::new(Context) AttrTy(Context, AL, AL.getTCBName()); +} + +EnforceTCBAttr *Sema::mergeEnforceTCBAttr(Decl *D, const EnforceTCBAttr &AL) { + return mergeEnforceTCBAttrImpl<EnforceTCBAttr, EnforceTCBLeafAttr>( + *this, D, AL); +} + +EnforceTCBLeafAttr *Sema::mergeEnforceTCBLeafAttr( + Decl *D, const EnforceTCBLeafAttr &AL) { + return mergeEnforceTCBAttrImpl<EnforceTCBLeafAttr, EnforceTCBAttr>( + *this, D, AL); +} + //===----------------------------------------------------------------------===// // Top Level Sema Entry Points //===----------------------------------------------------------------------===// @@ -6815,7 +7639,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, AL.isDeclspecAttribute() ? (unsigned)diag::warn_unhandled_ms_attribute_ignored : (unsigned)diag::warn_unknown_attribute_ignored) - << AL; + << AL << AL.getRange(); return; } @@ -6939,19 +7763,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handlePassObjectSizeAttr(S, D, AL); break; case ParsedAttr::AT_Constructor: - if (S.Context.getTargetInfo().getTriple().isOSAIX()) - llvm::report_fatal_error( - "'constructor' attribute is not yet supported on AIX"); - else handleConstructorAttr(S, D, AL); break; case ParsedAttr::AT_Deprecated: handleDeprecatedAttr(S, D, AL); break; case ParsedAttr::AT_Destructor: - if (S.Context.getTargetInfo().getTriple().isOSAIX()) - llvm::report_fatal_error("'destructor' attribute is not yet supported on AIX"); - else handleDestructorAttr(S, D, AL); break; case ParsedAttr::AT_EnableIf: @@ -6990,16 +7807,21 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_Callback: handleCallbackAttr(S, D, AL); break; + case ParsedAttr::AT_CalledOnce: + handleCalledOnceAttr(S, D, AL); + break; case ParsedAttr::AT_CUDAGlobal: handleGlobalAttr(S, D, AL); break; case ParsedAttr::AT_CUDADevice: - handleSimpleAttributeWithExclusions<CUDADeviceAttr, CUDAGlobalAttr>(S, D, - AL); + handleDeviceAttr(S, D, AL); break; case ParsedAttr::AT_CUDAHost: handleSimpleAttributeWithExclusions<CUDAHostAttr, CUDAGlobalAttr>(S, D, AL); break; + case ParsedAttr::AT_HIPManaged: + handleManagedAttr(S, D, AL); + break; case ParsedAttr::AT_CUDADeviceBuiltinSurfaceType: handleSimpleAttributeWithExclusions<CUDADeviceBuiltinSurfaceTypeAttr, CUDADeviceBuiltinTextureTypeAttr>(S, D, @@ -7058,6 +7880,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_AnyX86NoCfCheck: handleNoCfCheckAttr(S, D, AL); break; + case ParsedAttr::AT_Leaf: + handleSimpleAttribute<LeafAttr>(S, D, AL); + break; case ParsedAttr::AT_NoThrow: if (!AL.isUsedAsTypeAttr()) handleSimpleAttribute<NoThrowAttr>(S, D, AL); @@ -7098,6 +7923,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_ObjCBoxable: handleObjCBoxable(S, D, AL); break; + case ParsedAttr::AT_NSErrorDomain: + handleNSErrorDomain(S, D, AL); + break; case ParsedAttr::AT_CFAuditedTransfer: handleSimpleAttributeWithExclusions<CFAuditedTransferAttr, CFUnknownTransferAttr>(S, D, AL); @@ -7155,6 +7983,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_Packed: handlePackedAttr(S, D, AL); break; + case ParsedAttr::AT_PreferredName: + handlePreferredName(S, D, AL); + break; case ParsedAttr::AT_Section: handleSectionAttr(S, D, AL); break; @@ -7179,9 +8010,15 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_Unavailable: handleAttrWithMessage<UnavailableAttr>(S, D, AL); break; + case ParsedAttr::AT_Assumption: + handleAssumumptionAttr(S, D, AL); + break; case ParsedAttr::AT_ObjCDirect: handleObjCDirectAttr(S, D, AL); break; + case ParsedAttr::AT_ObjCNonRuntimeProtocol: + handleObjCNonRuntimeProtocolAttr(S, D, AL); + break; case ParsedAttr::AT_ObjCDirectMembers: handleObjCDirectMembersAttr(S, D, AL); handleSimpleAttribute<ObjCDirectMembersAttr>(S, D, AL); @@ -7200,6 +8037,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleSimpleAttributeWithExclusions<DisableTailCallsAttr, NakedAttr>(S, D, AL); break; + case ParsedAttr::AT_NoMerge: + handleSimpleAttribute<NoMergeAttr>(S, D, AL); + break; case ParsedAttr::AT_Visibility: handleVisibilityAttr(S, D, AL, false); break; @@ -7397,6 +8237,38 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleTypeTagForDatatypeAttr(S, D, AL); break; + // Swift attributes. + case ParsedAttr::AT_SwiftAsyncName: + handleSwiftAsyncName(S, D, AL); + break; + case ParsedAttr::AT_SwiftAttr: + handleSwiftAttrAttr(S, D, AL); + break; + case ParsedAttr::AT_SwiftBridge: + handleSwiftBridge(S, D, AL); + break; + case ParsedAttr::AT_SwiftBridgedTypedef: + handleSimpleAttribute<SwiftBridgedTypedefAttr>(S, D, AL); + break; + case ParsedAttr::AT_SwiftError: + handleSwiftError(S, D, AL); + break; + case ParsedAttr::AT_SwiftName: + handleSwiftName(S, D, AL); + break; + case ParsedAttr::AT_SwiftNewType: + handleSwiftNewType(S, D, AL); + break; + case ParsedAttr::AT_SwiftObjCMembers: + handleSimpleAttribute<SwiftObjCMembersAttr>(S, D, AL); + break; + case ParsedAttr::AT_SwiftPrivate: + handleSimpleAttribute<SwiftPrivateAttr>(S, D, AL); + break; + case ParsedAttr::AT_SwiftAsync: + handleSwiftAsyncAttr(S, D, AL); + break; + // XRay attributes. case ParsedAttr::AT_XRayLogArgs: handleXRayLogArgsAttr(S, D, AL); @@ -7446,6 +8318,14 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_UseHandle: handleHandleAttr<UseHandleAttr>(S, D, AL); break; + + case ParsedAttr::AT_EnforceTCB: + handleEnforceTCBAttr<EnforceTCBAttr, EnforceTCBLeafAttr>(S, D, AL); + break; + + case ParsedAttr::AT_EnforceTCBLeaf: + handleEnforceTCBAttr<EnforceTCBLeafAttr, EnforceTCBAttr>(S, D, AL); + break; } } @@ -7600,8 +8480,8 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, NewFD = FunctionDecl::Create( FD->getASTContext(), FD->getDeclContext(), Loc, Loc, DeclarationName(II), FD->getType(), FD->getTypeSourceInfo(), SC_None, - false /*isInlineSpecified*/, FD->hasPrototype(), CSK_unspecified, - FD->getTrailingRequiresClause()); + false /*isInlineSpecified*/, FD->hasPrototype(), + ConstexprSpecKind::Unspecified, FD->getTrailingRequiresClause()); NewD = NewFD; if (FD->getQualifier()) |