aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaDeclAttr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaDeclAttr.cpp')
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp1060
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())