summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaDeclAttr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaDeclAttr.cpp')
-rw-r--r--lib/Sema/SemaDeclAttr.cpp1150
1 files changed, 848 insertions, 302 deletions
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 25af73a..cbc940f 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -78,6 +78,13 @@ static bool isFunctionOrMethodOrBlock(const Decl *d) {
return isa<BlockDecl>(d);
}
+/// Return true if the given decl has a declarator that should have
+/// been processed by Sema::GetTypeForDeclarator.
+static bool hasDeclarator(const Decl *d) {
+ // In some sense, TypedefDecl really *ought* to be a DeclaratorDecl.
+ return isa<DeclaratorDecl>(d) || isa<BlockDecl>(d) || isa<TypedefDecl>(d);
+}
+
/// hasFunctionProto - Return true if the given decl has a argument
/// information. This decl should have already passed
/// isFunctionOrMethod or isFunctionOrMethodOrBlock.
@@ -127,6 +134,12 @@ static bool isFunctionOrMethodVariadic(const Decl *d) {
}
}
+static bool isInstanceMethod(const Decl *d) {
+ if (const CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(d))
+ return MethodDecl->isInstance();
+ return false;
+}
+
static inline bool isNSStringType(QualType T, ASTContext &Ctx) {
const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
if (!PT)
@@ -191,7 +204,7 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
- sizeExpr = static_cast<Expr *>(Attr.getArg(0));
+ sizeExpr = Attr.getArg(0);
}
// Instantiate/Install the vector type, and let Sema build the type for us.
@@ -242,7 +255,7 @@ static void HandleIBAction(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- S.Diag(Attr.getLoc(), diag::err_attribute_ibaction) << Attr.getName();
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ibaction) << Attr.getName();
}
static void HandleIBOutlet(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -259,7 +272,7 @@ static void HandleIBOutlet(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet) << Attr.getName();
+ S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName();
}
static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr,
@@ -274,7 +287,7 @@ static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr,
// The IBOutletCollection attributes only apply to instance variables of
// Objective-C classes.
if (!(isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d))) {
- S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet) << Attr.getName();
+ S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName();
return;
}
if (const ValueDecl *VD = dyn_cast<ValueDecl>(d))
@@ -323,7 +336,10 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- unsigned NumArgs = getFunctionOrMethodNumArgs(d);
+ // In C++ the implicit 'this' function parameter also counts, and they are
+ // counted from one.
+ bool HasImplicitThisParam = isInstanceMethod(d);
+ unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam;
// The nonnull attribute only applies to pointers.
llvm::SmallVector<unsigned, 10> NonNullArgs;
@@ -333,7 +349,7 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// The argument must be an integer constant expression.
- Expr *Ex = static_cast<Expr *>(*I);
+ Expr *Ex = *I;
llvm::APSInt ArgNum(32);
if (Ex->isTypeDependent() || Ex->isValueDependent() ||
!Ex->isIntegerConstantExpr(ArgNum, S.Context)) {
@@ -351,9 +367,18 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
--x;
+ if (HasImplicitThisParam) {
+ if (x == 0) {
+ S.Diag(Attr.getLoc(),
+ diag::err_attribute_invalid_implicit_this_argument)
+ << "nonnull" << Ex->getSourceRange();
+ return;
+ }
+ --x;
+ }
// Is the function argument a pointer type?
- QualType T = getFunctionOrMethodArgType(d, x);
+ QualType T = getFunctionOrMethodArgType(d, x).getNonReferenceType();
if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
// FIXME: Should also highlight argument in decl.
S.Diag(Attr.getLoc(), diag::warn_nonnull_pointers_only)
@@ -368,13 +393,30 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// arguments have a nonnull attribute.
if (NonNullArgs.empty()) {
for (unsigned I = 0, E = getFunctionOrMethodNumArgs(d); I != E; ++I) {
- QualType T = getFunctionOrMethodArgType(d, I);
+ QualType T = getFunctionOrMethodArgType(d, I).getNonReferenceType();
if (T->isAnyPointerType() || T->isBlockPointerType())
NonNullArgs.push_back(I);
+ else if (const RecordType *UT = T->getAsUnionType()) {
+ if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) {
+ RecordDecl *UD = UT->getDecl();
+ for (RecordDecl::field_iterator it = UD->field_begin(),
+ itend = UD->field_end(); it != itend; ++it) {
+ T = it->getType();
+ if (T->isAnyPointerType() || T->isBlockPointerType()) {
+ NonNullArgs.push_back(I);
+ break;
+ }
+ }
+ }
+ }
}
+ // No pointer arguments?
if (NonNullArgs.empty()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers);
+ // Warn the trivial case only if attribute is not coming from a
+ // macro instantiation.
+ if (Attr.getLoc().isFileID())
+ S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers);
return;
}
}
@@ -437,7 +479,10 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) {
return;
}
- unsigned NumArgs = getFunctionOrMethodNumArgs(d);
+ // In C++ the implicit 'this' function parameter also counts, and they are
+ // counted from one.
+ bool HasImplicitThisParam = isInstanceMethod(d);
+ unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam;
llvm::StringRef Module = AL.getParameterName()->getName();
@@ -450,7 +495,7 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) {
for (AttributeList::arg_iterator I = AL.arg_begin(), E = AL.arg_end(); I != E;
++I) {
- Expr *IdxExpr = static_cast<Expr *>(*I);
+ Expr *IdxExpr = *I;
llvm::APSInt ArgNum(32);
if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent()
|| !IdxExpr->isIntegerConstantExpr(ArgNum, S.Context)) {
@@ -467,6 +512,15 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) {
continue;
}
--x;
+ if (HasImplicitThisParam) {
+ if (x == 0) {
+ S.Diag(AL.getLoc(), diag::err_attribute_invalid_implicit_this_argument)
+ << "ownership" << IdxExpr->getSourceRange();
+ return;
+ }
+ --x;
+ }
+
switch (K) {
case OwnershipAttr::Takes:
case OwnershipAttr::Holds: {
@@ -485,7 +539,7 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) {
case OwnershipAttr::Returns: {
if (AL.getNumArgs() > 1) {
// Is the function argument an integer type?
- Expr *IdxExpr = static_cast<Expr *>(AL.getArg(0));
+ Expr *IdxExpr = AL.getArg(0);
llvm::APSInt ArgNum(32);
if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent()
|| !IdxExpr->isIntegerConstantExpr(ArgNum, S.Context)) {
@@ -532,11 +586,23 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) {
start, size));
}
-static bool isStaticVarOrStaticFunciton(Decl *D) {
- if (VarDecl *VD = dyn_cast<VarDecl>(D))
- return VD->getStorageClass() == SC_Static;
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- return FD->getStorageClass() == SC_Static;
+/// Whether this declaration has internal linkage for the purposes of
+/// things that want to complain about things not have internal linkage.
+static bool hasEffectivelyInternalLinkage(NamedDecl *D) {
+ switch (D->getLinkage()) {
+ case NoLinkage:
+ case InternalLinkage:
+ return true;
+
+ // Template instantiations that go from external to unique-external
+ // shouldn't get diagnosed.
+ case UniqueExternalLinkage:
+ return true;
+
+ case ExternalLinkage:
+ return false;
+ }
+ llvm_unreachable("unknown linkage kind!");
return false;
}
@@ -547,6 +613,14 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
+ if (!isa<VarDecl>(d) && !isa<FunctionDecl>(d)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << 2 /*variables and functions*/;
+ return;
+ }
+
+ NamedDecl *nd = cast<NamedDecl>(d);
+
// gcc rejects
// class c {
// static int a __attribute__((weakref ("v2")));
@@ -560,7 +634,7 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) {
const DeclContext *Ctx = d->getDeclContext()->getRedeclContext();
if (!Ctx->isFileContext()) {
S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_global_context) <<
- dyn_cast<NamedDecl>(d)->getNameAsString();
+ nd->getNameAsString();
return;
}
@@ -582,9 +656,8 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// This looks like a bug in gcc. We reject that for now. We should revisit
// it if this behaviour is actually used.
- if (!isStaticVarOrStaticFunciton(d)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_static) <<
- dyn_cast<NamedDecl>(d)->getNameAsString();
+ if (!hasEffectivelyInternalLinkage(nd)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_static);
return;
}
@@ -593,7 +666,7 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// Should we? How to check that weakref is before or after alias?
if (Attr.getNumArgs() == 1) {
- Expr *Arg = static_cast<Expr*>(Attr.getArg(0));
+ Expr *Arg = Attr.getArg(0);
Arg = Arg->IgnoreParenCasts();
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
@@ -604,7 +677,8 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
// GCC will accept anything as the argument of weakref. Should we
// check for an existing decl?
- d->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context, Str->getString()));
+ d->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context,
+ Str->getString()));
}
d->addAttr(::new (S.Context) WeakRefAttr(Attr.getLoc(), S.Context));
@@ -617,7 +691,7 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- Expr *Arg = static_cast<Expr*>(Attr.getArg(0));
+ Expr *Arg = Attr.getArg(0);
Arg = Arg->IgnoreParenCasts();
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
@@ -627,14 +701,37 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
+ if (S.Context.Target.getTriple().getOS() == llvm::Triple::Darwin) {
+ S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_darwin);
+ return;
+ }
+
// FIXME: check if target symbol exists in current file
- d->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context, Str->getString()));
+ d->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context,
+ Str->getString()));
+}
+
+static void HandleNakedAttr(Decl *d, const AttributeList &Attr,
+ Sema &S) {
+ // Check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (!isa<FunctionDecl>(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) NakedAttr(Attr.getLoc(), S.Context));
}
static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
Sema &S) {
- // check the attribute arguments.
+ // Check the attribute arguments.
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
@@ -642,7 +739,7 @@ static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
if (!isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ << Attr.getName() << 0 /*function*/;
return;
}
@@ -650,7 +747,7 @@ static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
}
static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- // check the attribute arguments.
+ // Check the attribute arguments.
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
@@ -667,10 +764,56 @@ static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::warn_attribute_malloc_pointer_only);
}
-static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- /* Diagnostics (if any) was emitted by Sema::ProcessFnAttr(). */
+static void HandleMayAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) MayAliasAttr(Attr.getLoc(), S.Context));
+}
+
+static void HandleNoCommonAttr(Decl *d, const AttributeList &Attr, Sema &S) {
assert(Attr.isInvalid() == false);
- d->addAttr(::new (S.Context) NoReturnAttr(Attr.getLoc(), S.Context));
+ if (isa<VarDecl>(d))
+ d->addAttr(::new (S.Context) NoCommonAttr(Attr.getLoc(), S.Context));
+ else
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 12 /* variable */;
+}
+
+static void HandleCommonAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ assert(Attr.isInvalid() == false);
+ if (isa<VarDecl>(d))
+ d->addAttr(::new (S.Context) CommonAttr(Attr.getLoc(), S.Context));
+ else
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 12 /* variable */;
+}
+
+static void HandleNoReturnAttr(Decl *d, const AttributeList &attr, Sema &S) {
+ if (hasDeclarator(d)) return;
+
+ if (S.CheckNoReturnAttr(attr)) return;
+
+ if (!isa<ObjCMethodDecl>(d)) {
+ S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) NoReturnAttr(attr.getLoc(), S.Context));
+}
+
+bool Sema::CheckNoReturnAttr(const AttributeList &attr) {
+ if (attr.getNumArgs() != 0) {
+ Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ attr.setInvalid();
+ return true;
+ }
+
+ return false;
}
static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
@@ -705,10 +848,11 @@ static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr,
/*
Returning a Vector Class in Registers
- According to the PPU ABI specifications, a class with a single member of vector type is returned in
- memory when used as the return value of a function. This results in inefficient code when implementing
- vector classes. To return the value in a single vector register, add the vecreturn attribute to the class
- definition. This attribute is also applicable to struct types.
+ According to the PPU ABI specifications, a class with a single member of
+ vector type is returned in memory when used as the return value of a function.
+ This results in inefficient code when implementing vector classes. To return
+ the value in a single vector register, add the vecreturn attribute to the
+ class definition. This attribute is also applicable to struct types.
Example:
@@ -724,7 +868,7 @@ static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr,
return result; // This will be returned in a register
}
*/
- if (!isa<CXXRecordDecl>(d)) {
+ if (!isa<RecordDecl>(d)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << 9 /*class*/;
return;
@@ -735,6 +879,28 @@ static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr,
return;
}
+ RecordDecl *record = cast<RecordDecl>(d);
+ int count = 0;
+
+ if (!isa<CXXRecordDecl>(record)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_vecreturn_only_vector_member);
+ return;
+ }
+
+ if (!cast<CXXRecordDecl>(record)->isPOD()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_vecreturn_only_pod_record);
+ return;
+ }
+
+ for (RecordDecl::field_iterator iter = record->field_begin();
+ iter != record->field_end(); iter++) {
+ if ((count == 1) || !iter->getType()->isVectorType()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_vecreturn_only_vector_member);
+ return;
+ }
+ count++;
+ }
+
d->addAttr(::new (S.Context) VecReturnAttr(Attr.getLoc(), S.Context));
}
@@ -755,9 +921,9 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
if (!isa<VarDecl>(d) && !isa<ObjCIvarDecl>(d) && !isFunctionOrMethod(d) &&
- !isa<TypeDecl>(d)) {
+ !isa<TypeDecl>(d) && !isa<LabelDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 2 /*variable and function*/;
+ << Attr.getName() << 14 /*variable, function, labels*/;
return;
}
@@ -795,7 +961,7 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
int priority = 65535; // FIXME: Do not hardcode such constants.
if (Attr.getNumArgs() > 0) {
- Expr *E = static_cast<Expr *>(Attr.getArg(0));
+ Expr *E = Attr.getArg(0);
llvm::APSInt Idx(32);
if (E->isTypeDependent() || E->isValueDependent() ||
!E->isIntegerConstantExpr(Idx, S.Context)) {
@@ -812,7 +978,8 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) ConstructorAttr(Attr.getLoc(), S.Context, priority));
+ d->addAttr(::new (S.Context) ConstructorAttr(Attr.getLoc(), S.Context,
+ priority));
}
static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -825,7 +992,7 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
int priority = 65535; // FIXME: Do not hardcode such constants.
if (Attr.getNumArgs() > 0) {
- Expr *E = static_cast<Expr *>(Attr.getArg(0));
+ Expr *E = Attr.getArg(0);
llvm::APSInt Idx(32);
if (E->isTypeDependent() || E->isValueDependent() ||
!E->isIntegerConstantExpr(Idx, S.Context)) {
@@ -842,27 +1009,59 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) DestructorAttr(Attr.getLoc(), S.Context, priority));
+ d->addAttr(::new (S.Context) DestructorAttr(Attr.getLoc(), S.Context,
+ priority));
}
static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
+ int noArgs = Attr.getNumArgs();
+ if (noArgs > 1) {
+ S.Diag(Attr.getLoc(),
+ diag::err_attribute_wrong_number_arguments) << "0 or 1";
+ return;
+ }
+ // Handle the case where deprecated attribute has a text message.
+ StringLiteral *SE;
+ if (noArgs == 1) {
+ Expr *ArgExpr = Attr.getArg(0);
+ SE = dyn_cast<StringLiteral>(ArgExpr);
+ if (!SE) {
+ S.Diag(ArgExpr->getLocStart(),
+ diag::err_attribute_not_string) << "deprecated";
+ return;
+ }
}
+ else
+ SE = StringLiteral::CreateEmpty(S.Context, 1);
- d->addAttr(::new (S.Context) DeprecatedAttr(Attr.getLoc(), S.Context));
+ d->addAttr(::new (S.Context) DeprecatedAttr(Attr.getLoc(), S.Context,
+ SE->getString()));
}
static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ int noArgs = Attr.getNumArgs();
+ if (noArgs > 1) {
+ S.Diag(Attr.getLoc(),
+ diag::err_attribute_wrong_number_arguments) << "0 or 1";
return;
}
-
- d->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context));
+ // Handle the case where unavailable attribute has a text message.
+ StringLiteral *SE;
+ if (noArgs == 1) {
+ Expr *ArgExpr = Attr.getArg(0);
+ SE = dyn_cast<StringLiteral>(ArgExpr);
+ if (!SE) {
+ S.Diag(ArgExpr->getLocStart(),
+ diag::err_attribute_not_string) << "unavailable";
+ return;
+ }
+ }
+ else
+ SE = StringLiteral::CreateEmpty(S.Context, 1);
+ d->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context,
+ SE->getString()));
}
static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -872,7 +1071,7 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- Expr *Arg = static_cast<Expr*>(Attr.getArg(0));
+ Expr *Arg = Attr.getArg(0);
Arg = Arg->IgnoreParenCasts();
StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
@@ -982,7 +1181,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
int sentinel = 0;
if (Attr.getNumArgs() > 0) {
- Expr *E = static_cast<Expr *>(Attr.getArg(0));
+ Expr *E = Attr.getArg(0);
llvm::APSInt Idx(32);
if (E->isTypeDependent() || E->isValueDependent() ||
!E->isIntegerConstantExpr(Idx, S.Context)) {
@@ -1001,7 +1200,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
int nullPos = 0;
if (Attr.getNumArgs() > 1) {
- Expr *E = static_cast<Expr *>(Attr.getArg(1));
+ Expr *E = Attr.getArg(1);
llvm::APSInt Idx(32);
if (E->isTypeDependent() || E->isValueDependent() ||
!E->isIntegerConstantExpr(Idx, S.Context)) {
@@ -1046,7 +1245,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
QualType Ty = V->getType();
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(d)
- : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
+ : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
if (!cast<FunctionProtoType>(FT)->isVariadic()) {
int m = Ty->isFunctionPointerType() ? 0 : 1;
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m;
@@ -1062,7 +1261,8 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< Attr.getName() << 6 /*function, method or block */;
return;
}
- d->addAttr(::new (S.Context) SentinelAttr(Attr.getLoc(), S.Context, sentinel, nullPos));
+ d->addAttr(::new (S.Context) SentinelAttr(Attr.getLoc(), S.Context, sentinel,
+ nullPos));
}
static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) {
@@ -1093,28 +1293,28 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S)
D->addAttr(::new (S.Context) WarnUnusedResultAttr(Attr.getLoc(), S.Context));
}
-static void HandleWeakAttr(Decl *D, const AttributeList &Attr, Sema &S) {
+static void HandleWeakAttr(Decl *d, const AttributeList &attr, Sema &S) {
// check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ if (attr.getNumArgs() != 0) {
+ S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
return;
}
- /* weak only applies to non-static declarations */
- if (isStaticVarOrStaticFunciton(D)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_weak_static) <<
- dyn_cast<NamedDecl>(D)->getNameAsString();
+ if (!isa<VarDecl>(d) && !isa<FunctionDecl>(d)) {
+ S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << attr.getName() << 2 /*variables and functions*/;
return;
}
- // TODO: could also be applied to methods?
- if (!isa<FunctionDecl>(D) && !isa<VarDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 2 /*variable and function*/;
+ NamedDecl *nd = cast<NamedDecl>(d);
+
+ // 'weak' only applies to declarations with external linkage.
+ if (hasEffectivelyInternalLinkage(nd)) {
+ S.Diag(attr.getLoc(), diag::err_attribute_weak_static);
return;
}
- D->addAttr(::new (S.Context) WeakAttr(Attr.getLoc(), S.Context));
+ nd->addAttr(::new (S.Context) WeakAttr(attr.getLoc(), S.Context));
}
static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
@@ -1163,7 +1363,7 @@ static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr,
unsigned WGSize[3];
for (unsigned i = 0; i < 3; ++i) {
- Expr *E = static_cast<Expr *>(Attr.getArg(i));
+ Expr *E = Attr.getArg(i);
llvm::APSInt ArgNum(32);
if (E->isTypeDependent() || E->isValueDependent() ||
!E->isIntegerConstantExpr(ArgNum, S.Context)) {
@@ -1187,7 +1387,7 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// Make sure that there is a string literal as the sections's single
// argument.
- Expr *ArgExpr = static_cast<Expr *>(Attr.getArg(0));
+ Expr *ArgExpr = Attr.getArg(0);
StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr);
if (!SE) {
S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) << "section";
@@ -1208,7 +1408,8 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
return;
}
- D->addAttr(::new (S.Context) SectionAttr(Attr.getLoc(), S.Context, SE->getString()));
+ D->addAttr(::new (S.Context) SectionAttr(Attr.getLoc(), S.Context,
+ SE->getString()));
}
@@ -1262,27 +1463,27 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// Look up the function
// FIXME: Lookup probably isn't looking in the right place
- // FIXME: The lookup source location should be in the attribute, not the
- // start of the attribute.
NamedDecl *CleanupDecl
- = S.LookupSingleName(S.TUScope, Attr.getParameterName(), Attr.getLoc(),
- Sema::LookupOrdinaryName);
+ = S.LookupSingleName(S.TUScope, Attr.getParameterName(),
+ Attr.getParameterLoc(), Sema::LookupOrdinaryName);
if (!CleanupDecl) {
- S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_found) <<
+ S.Diag(Attr.getParameterLoc(), diag::err_attribute_cleanup_arg_not_found) <<
Attr.getParameterName();
return;
}
FunctionDecl *FD = dyn_cast<FunctionDecl>(CleanupDecl);
if (!FD) {
- S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_function) <<
- Attr.getParameterName();
+ S.Diag(Attr.getParameterLoc(),
+ diag::err_attribute_cleanup_arg_not_function)
+ << Attr.getParameterName();
return;
}
if (FD->getNumParams() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_func_must_take_one_arg) <<
- Attr.getParameterName();
+ S.Diag(Attr.getParameterLoc(),
+ diag::err_attribute_cleanup_func_must_take_one_arg)
+ << Attr.getParameterName();
return;
}
@@ -1290,14 +1491,16 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// If this ever proves to be a problem it should be easy to fix.
QualType Ty = S.Context.getPointerType(VD->getType());
QualType ParamTy = FD->getParamDecl(0)->getType();
- if (S.CheckAssignmentConstraints(ParamTy, Ty) != Sema::Compatible) {
- S.Diag(Attr.getLoc(),
+ if (S.CheckAssignmentConstraints(FD->getParamDecl(0)->getLocation(),
+ ParamTy, Ty) != Sema::Compatible) {
+ S.Diag(Attr.getParameterLoc(),
diag::err_attribute_cleanup_func_arg_incompatible_type) <<
Attr.getParameterName() << ParamTy << Ty;
return;
}
d->addAttr(::new (S.Context) CleanupAttr(Attr.getLoc(), S.Context, FD));
+ S.MarkDeclarationReferenced(Attr.getParameterLoc(), FD);
}
/// Handle __attribute__((format_arg((idx)))) attribute based on
@@ -1312,12 +1515,15 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< Attr.getName() << 0 /*function*/;
return;
}
- // FIXME: in C++ the implicit 'this' function parameter also counts. this is
- // needed in order to be compatible with GCC the index must start with 1.
- unsigned NumArgs = getFunctionOrMethodNumArgs(d);
+
+ // In C++ the implicit 'this' function parameter also counts, and they are
+ // counted from one.
+ bool HasImplicitThisParam = isInstanceMethod(d);
+ unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam;
unsigned FirstIdx = 1;
+
// checks for the 2nd argument
- Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0));
+ Expr *IdxExpr = Attr.getArg(0);
llvm::APSInt Idx(32);
if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
@@ -1334,6 +1540,15 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
unsigned ArgIdx = Idx.getZExtValue() - 1;
+ if (HasImplicitThisParam) {
+ if (ArgIdx == 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_invalid_implicit_this_argument)
+ << "format_arg" << IdxExpr->getSourceRange();
+ return;
+ }
+ ArgIdx--;
+ }
+
// make sure the format string is really a string
QualType Ty = getFunctionOrMethodArgType(d, ArgIdx);
@@ -1360,7 +1575,8 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- d->addAttr(::new (S.Context) FormatArgAttr(Attr.getLoc(), S.Context, Idx.getZExtValue()));
+ d->addAttr(::new (S.Context) FormatArgAttr(Attr.getLoc(), S.Context,
+ Idx.getZExtValue()));
}
enum FormatAttrKind {
@@ -1387,7 +1603,8 @@ static FormatAttrKind getFormatAttrKind(llvm::StringRef Format) {
if (Format == "scanf" || Format == "printf" || Format == "printf0" ||
Format == "strfmon" || Format == "cmn_err" || Format == "strftime" ||
Format == "NSString" || Format == "CFString" || Format == "vcmn_err" ||
- Format == "zcmn_err")
+ Format == "zcmn_err" ||
+ Format == "kprintf") // OpenBSD.
return SupportedFormat;
if (Format == "gcc_diag" || Format == "gcc_cdiag" ||
@@ -1425,7 +1642,7 @@ static void HandleInitPriorityAttr(Decl *d, const AttributeList &Attr,
Attr.setInvalid();
return;
}
- Expr *priorityExpr = static_cast<Expr *>(Attr.getArg(0));
+ Expr *priorityExpr = Attr.getArg(0);
llvm::APSInt priority(32);
if (priorityExpr->isTypeDependent() || priorityExpr->isValueDependent() ||
@@ -1442,7 +1659,8 @@ static void HandleInitPriorityAttr(Decl *d, const AttributeList &Attr,
Attr.setInvalid();
return;
}
- d->addAttr(::new (S.Context) InitPriorityAttr(Attr.getLoc(), S.Context, prioritynum));
+ d->addAttr(::new (S.Context) InitPriorityAttr(Attr.getLoc(), S.Context,
+ prioritynum));
}
/// Handle __attribute__((format(type,idx,firstarg))) attributes based on
@@ -1466,7 +1684,10 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- unsigned NumArgs = getFunctionOrMethodNumArgs(d);
+ // In C++ the implicit 'this' function parameter also counts, and they are
+ // counted from one.
+ bool HasImplicitThisParam = isInstanceMethod(d);
+ unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam;
unsigned FirstIdx = 1;
llvm::StringRef Format = Attr.getParameterName()->getName();
@@ -1488,7 +1709,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
// checks for the 2nd argument
- Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0));
+ Expr *IdxExpr = Attr.getArg(0);
llvm::APSInt Idx(32);
if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
@@ -1497,16 +1718,6 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- // FIXME: We should handle the implicit 'this' parameter in a more generic
- // way that can be used for other arguments.
- bool HasImplicitThisParam = false;
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(d)) {
- if (MD->isInstance()) {
- HasImplicitThisParam = true;
- NumArgs++;
- }
- }
-
if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
<< "format" << 2 << IdxExpr->getSourceRange();
@@ -1518,8 +1729,9 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (HasImplicitThisParam) {
if (ArgIdx == 0) {
- S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
- << "a string type" << IdxExpr->getSourceRange();
+ S.Diag(Attr.getLoc(),
+ diag::err_format_attribute_implicit_this_format_string)
+ << IdxExpr->getSourceRange();
return;
}
ArgIdx--;
@@ -1552,7 +1764,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
// check the 3rd argument
- Expr *FirstArgExpr = static_cast<Expr *>(Attr.getArg(1));
+ Expr *FirstArgExpr = Attr.getArg(1);
llvm::APSInt FirstArg(32);
if (FirstArgExpr->isTypeDependent() || FirstArgExpr->isValueDependent() ||
!FirstArgExpr->isIntegerConstantExpr(FirstArg, S.Context)) {
@@ -1665,7 +1877,7 @@ static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
return;
}
- Expr *ArgExpr = static_cast<Expr *>(Attr.getArg(0));
+ Expr *ArgExpr = Attr.getArg(0);
StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr);
// Make sure that there is a string literal as the annotation's single
@@ -1674,7 +1886,8 @@ static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) {
S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate";
return;
}
- d->addAttr(::new (S.Context) AnnotateAttr(Attr.getLoc(), S.Context, SE->getString()));
+ d->addAttr(::new (S.Context) AnnotateAttr(Attr.getLoc(), S.Context,
+ SE->getString()));
}
static void HandleAlignedAttr(Decl *D, const AttributeList &Attr, Sema &S) {
@@ -1693,7 +1906,7 @@ static void HandleAlignedAttr(Decl *D, const AttributeList &Attr, Sema &S) {
return;
}
- S.AddAlignedAttr(Attr.getLoc(), D, static_cast<Expr *>(Attr.getArg(0)));
+ S.AddAlignedAttr(Attr.getLoc(), D, Attr.getArg(0));
}
void Sema::AddAlignedAttr(SourceLocation AttrLoc, Decl *D, Expr *E) {
@@ -1943,7 +2156,123 @@ static void HandleNoInstrumentFunctionAttr(Decl *d, const AttributeList &Attr,
return;
}
- d->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getLoc(), S.Context));
+ d->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getLoc(),
+ S.Context));
+}
+
+static void HandleConstantAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ if (S.LangOpts.CUDA) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (!isa<VarDecl>(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 12 /*variable*/;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) CUDAConstantAttr(Attr.getLoc(), S.Context));
+ } else {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "constant";
+ }
+}
+
+static void HandleDeviceAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ if (S.LangOpts.CUDA) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (!isa<FunctionDecl>(d) && !isa<VarDecl>(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 2 /*variable and function*/;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) CUDADeviceAttr(Attr.getLoc(), S.Context));
+ } else {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "device";
+ }
+}
+
+static void HandleGlobalAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ if (S.LangOpts.CUDA) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (!isa<FunctionDecl>(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ FunctionDecl *FD = cast<FunctionDecl>(d);
+ if (!FD->getResultType()->isVoidType()) {
+ TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens();
+ if (FunctionTypeLoc* FTL = dyn_cast<FunctionTypeLoc>(&TL)) {
+ S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return)
+ << FD->getType()
+ << FixItHint::CreateReplacement(FTL->getResultLoc().getSourceRange(),
+ "void");
+ } else {
+ S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return)
+ << FD->getType();
+ }
+ return;
+ }
+
+ d->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getLoc(), S.Context));
+ } else {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "global";
+ }
+}
+
+static void HandleHostAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ if (S.LangOpts.CUDA) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (!isa<FunctionDecl>(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) CUDAHostAttr(Attr.getLoc(), S.Context));
+ } else {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "host";
+ }
+}
+
+static void HandleSharedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ if (S.LangOpts.CUDA) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ if (!isa<VarDecl>(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 12 /*variable*/;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) CUDASharedAttr(Attr.getLoc(), S.Context));
+ } else {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "shared";
+ }
}
static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -1968,26 +2297,36 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
d->addAttr(::new (S.Context) GNUInlineAttr(Attr.getLoc(), S.Context));
}
-static void HandleCallConvAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- // Diagnostic is emitted elsewhere: here we store the (valid) Attr
+static void HandleCallConvAttr(Decl *d, const AttributeList &attr, Sema &S) {
+ if (hasDeclarator(d)) return;
+
+ // Diagnostic is emitted elsewhere: here we store the (valid) attr
// in the Decl node for syntactic reasoning, e.g., pretty-printing.
- assert(Attr.isInvalid() == false);
+ CallingConv CC;
+ if (S.CheckCallingConvAttr(attr, CC))
+ return;
- switch (Attr.getKind()) {
+ if (!isa<ObjCMethodDecl>(d)) {
+ S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ switch (attr.getKind()) {
case AttributeList::AT_fastcall:
- d->addAttr(::new (S.Context) FastCallAttr(Attr.getLoc(), S.Context));
+ d->addAttr(::new (S.Context) FastCallAttr(attr.getLoc(), S.Context));
return;
case AttributeList::AT_stdcall:
- d->addAttr(::new (S.Context) StdCallAttr(Attr.getLoc(), S.Context));
+ d->addAttr(::new (S.Context) StdCallAttr(attr.getLoc(), S.Context));
return;
case AttributeList::AT_thiscall:
- d->addAttr(::new (S.Context) ThisCallAttr(Attr.getLoc(), S.Context));
+ d->addAttr(::new (S.Context) ThisCallAttr(attr.getLoc(), S.Context));
return;
case AttributeList::AT_cdecl:
- d->addAttr(::new (S.Context) CDeclAttr(Attr.getLoc(), S.Context));
+ d->addAttr(::new (S.Context) CDeclAttr(attr.getLoc(), S.Context));
return;
case AttributeList::AT_pascal:
- d->addAttr(::new (S.Context) PascalAttr(Attr.getLoc(), S.Context));
+ d->addAttr(::new (S.Context) PascalAttr(attr.getLoc(), S.Context));
return;
default:
llvm_unreachable("unexpected attribute kind");
@@ -1995,214 +2334,336 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
}
-static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- // check the attribute arguments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
- return;
+static void HandleOpenCLKernelAttr(Decl *d, const AttributeList &Attr, Sema &S){
+ assert(Attr.isInvalid() == false);
+ d->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getLoc(), S.Context));
+}
+
+bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
+ if (attr.isInvalid())
+ return true;
+
+ if (attr.getNumArgs() != 0) {
+ Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ attr.setInvalid();
+ return true;
}
- if (!isFunctionOrMethod(d)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ // TODO: diagnose uses of these conventions on the wrong target.
+ switch (attr.getKind()) {
+ case AttributeList::AT_cdecl: CC = CC_C; break;
+ case AttributeList::AT_fastcall: CC = CC_X86FastCall; break;
+ case AttributeList::AT_stdcall: CC = CC_X86StdCall; break;
+ case AttributeList::AT_thiscall: CC = CC_X86ThisCall; break;
+ case AttributeList::AT_pascal: CC = CC_X86Pascal; break;
+ default: llvm_unreachable("unexpected attribute kind"); return true;
+ }
+
+ return false;
+}
+
+static void HandleRegparmAttr(Decl *d, const AttributeList &attr, Sema &S) {
+ if (hasDeclarator(d)) return;
+
+ unsigned numParams;
+ if (S.CheckRegparmAttr(attr, numParams))
+ return;
+
+ if (!isa<ObjCMethodDecl>(d)) {
+ S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << attr.getName() << 0 /*function*/;
return;
}
- Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0));
+ d->addAttr(::new (S.Context) RegparmAttr(attr.getLoc(), S.Context, numParams));
+}
+
+/// Checks a regparm attribute, returning true if it is ill-formed and
+/// otherwise setting numParams to the appropriate value.
+bool Sema::CheckRegparmAttr(const AttributeList &attr, unsigned &numParams) {
+ if (attr.isInvalid())
+ return true;
+
+ if (attr.getNumArgs() != 1) {
+ Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ attr.setInvalid();
+ return true;
+ }
+
+ Expr *NumParamsExpr = attr.getArg(0);
llvm::APSInt NumParams(32);
if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() ||
- !NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+ !NumParamsExpr->isIntegerConstantExpr(NumParams, Context)) {
+ Diag(attr.getLoc(), diag::err_attribute_argument_not_int)
<< "regparm" << NumParamsExpr->getSourceRange();
- return;
+ attr.setInvalid();
+ return true;
}
- if (S.Context.Target.getRegParmMax() == 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_regparm_wrong_platform)
+ if (Context.Target.getRegParmMax() == 0) {
+ Diag(attr.getLoc(), diag::err_attribute_regparm_wrong_platform)
<< NumParamsExpr->getSourceRange();
- return;
+ attr.setInvalid();
+ return true;
}
- if (NumParams.getLimitedValue(255) > S.Context.Target.getRegParmMax()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number)
- << S.Context.Target.getRegParmMax() << NumParamsExpr->getSourceRange();
- return;
+ numParams = NumParams.getZExtValue();
+ if (numParams > Context.Target.getRegParmMax()) {
+ Diag(attr.getLoc(), diag::err_attribute_regparm_invalid_number)
+ << Context.Target.getRegParmMax() << NumParamsExpr->getSourceRange();
+ attr.setInvalid();
+ return true;
}
- d->addAttr(::new (S.Context) RegparmAttr(Attr.getLoc(), S.Context,
- NumParams.getZExtValue()));
+ return false;
}
-static void HandleFinalAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- // check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
+static void HandleLaunchBoundsAttr(Decl *d, const AttributeList &Attr, Sema &S){
+ if (S.LangOpts.CUDA) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 1 && Attr.getNumArgs() != 2) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << "1 or 2";
+ return;
+ }
- if (!isa<CXXRecordDecl>(d)
- && (!isa<CXXMethodDecl>(d) || !cast<CXXMethodDecl>(d)->isVirtual())) {
- S.Diag(Attr.getLoc(),
- Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
- : diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 7 /*virtual method or class*/;
- return;
- }
-
- // FIXME: Conform to C++0x redeclaration rules.
-
- if (d->getAttr<FinalAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "final";
- return;
- }
+ if (!isFunctionOrMethod(d)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ Expr *MaxThreadsExpr = Attr.getArg(0);
+ llvm::APSInt MaxThreads(32);
+ if (MaxThreadsExpr->isTypeDependent() ||
+ MaxThreadsExpr->isValueDependent() ||
+ !MaxThreadsExpr->isIntegerConstantExpr(MaxThreads, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
+ << "launch_bounds" << 1 << MaxThreadsExpr->getSourceRange();
+ return;
+ }
- d->addAttr(::new (S.Context) FinalAttr(Attr.getLoc(), S.Context));
+ llvm::APSInt MinBlocks(32);
+ if (Attr.getNumArgs() > 1) {
+ Expr *MinBlocksExpr = Attr.getArg(1);
+ if (MinBlocksExpr->isTypeDependent() ||
+ MinBlocksExpr->isValueDependent() ||
+ !MinBlocksExpr->isIntegerConstantExpr(MinBlocks, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
+ << "launch_bounds" << 2 << MinBlocksExpr->getSourceRange();
+ return;
+ }
+ }
+
+ d->addAttr(::new (S.Context) CUDALaunchBoundsAttr(Attr.getLoc(), S.Context,
+ MaxThreads.getZExtValue(),
+ MinBlocks.getZExtValue()));
+ } else {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "launch_bounds";
+ }
}
//===----------------------------------------------------------------------===//
-// C++0x member checking attributes
+// Checker-specific attribute handlers.
//===----------------------------------------------------------------------===//
-static void HandleBaseCheckAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
-
- if (!isa<CXXRecordDecl>(d)) {
- S.Diag(Attr.getLoc(),
- Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
- : diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 9 /*class*/;
- return;
- }
-
- if (d->getAttr<BaseCheckAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "base_check";
- return;
- }
-
- d->addAttr(::new (S.Context) BaseCheckAttr(Attr.getLoc(), S.Context));
+static bool isValidSubjectOfNSAttribute(Sema &S, QualType type) {
+ return type->isObjCObjectPointerType() || S.Context.isObjCNSObjectType(type);
+}
+static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) {
+ return type->isPointerType() || isValidSubjectOfNSAttribute(S, type);
}
-static void HandleHidingAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+static void HandleNSConsumedAttr(Decl *d, const AttributeList &attr, Sema &S) {
+ ParmVarDecl *param = dyn_cast<ParmVarDecl>(d);
+ if (!param) {
+ S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
+ << SourceRange(attr.getLoc()) << attr.getName() << 4 /*parameter*/;
return;
}
- if (!isa<RecordDecl>(d->getDeclContext())) {
- // FIXME: It's not the type that's the problem
- S.Diag(Attr.getLoc(),
- Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
- : diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 11 /*member*/;
- return;
+ bool typeOK, cf;
+ if (attr.getKind() == AttributeList::AT_ns_consumed) {
+ typeOK = isValidSubjectOfNSAttribute(S, param->getType());
+ cf = false;
+ } else {
+ typeOK = isValidSubjectOfCFAttribute(S, param->getType());
+ cf = true;
}
- // FIXME: Conform to C++0x redeclaration rules.
-
- if (d->getAttr<HidingAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "hiding";
+ if (!typeOK) {
+ S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type)
+ << SourceRange(attr.getLoc()) << attr.getName() << cf;
return;
}
- d->addAttr(::new (S.Context) HidingAttr(Attr.getLoc(), S.Context));
+ if (cf)
+ param->addAttr(::new (S.Context) CFConsumedAttr(attr.getLoc(), S.Context));
+ else
+ param->addAttr(::new (S.Context) NSConsumedAttr(attr.getLoc(), S.Context));
}
-static void HandleOverrideAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
- return;
- }
-
- if (!isa<CXXMethodDecl>(d) || !cast<CXXMethodDecl>(d)->isVirtual()) {
- // FIXME: It's not the type that's the problem
- S.Diag(Attr.getLoc(),
- Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
- : diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 10 /*virtual method*/;
- return;
- }
-
- // FIXME: Conform to C++0x redeclaration rules.
-
- if (d->getAttr<OverrideAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "override";
+static void HandleNSConsumesSelfAttr(Decl *d, const AttributeList &attr,
+ Sema &S) {
+ if (!isa<ObjCMethodDecl>(d)) {
+ S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
+ << SourceRange(attr.getLoc()) << attr.getName() << 13 /*method*/;
return;
}
- d->addAttr(::new (S.Context) OverrideAttr(Attr.getLoc(), S.Context));
+ d->addAttr(::new (S.Context) NSConsumesSelfAttr(attr.getLoc(), S.Context));
}
-//===----------------------------------------------------------------------===//
-// Checker-specific attribute handlers.
-//===----------------------------------------------------------------------===//
-
-static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
+static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &attr,
Sema &S) {
- QualType RetTy;
+ QualType returnType;
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d))
- RetTy = MD->getResultType();
+ returnType = MD->getResultType();
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d))
- RetTy = FD->getResultType();
+ returnType = FD->getResultType();
else {
- SourceLocation L = Attr.getLoc();
S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
- << SourceRange(L, L) << Attr.getName() << 3 /* function or method */;
+ << SourceRange(attr.getLoc()) << attr.getName()
+ << 3 /* function or method */;
return;
}
- if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAs<PointerType>()
- || RetTy->getAs<ObjCObjectPointerType>())) {
- SourceLocation L = Attr.getLoc();
+ bool typeOK;
+ bool cf;
+ switch (attr.getKind()) {
+ default: llvm_unreachable("invalid ownership attribute"); return;
+ case AttributeList::AT_ns_returns_autoreleased:
+ case AttributeList::AT_ns_returns_retained:
+ case AttributeList::AT_ns_returns_not_retained:
+ typeOK = isValidSubjectOfNSAttribute(S, returnType);
+ cf = false;
+ break;
+
+ case AttributeList::AT_cf_returns_retained:
+ case AttributeList::AT_cf_returns_not_retained:
+ typeOK = isValidSubjectOfCFAttribute(S, returnType);
+ cf = true;
+ break;
+ }
+
+ if (!typeOK) {
S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
- << SourceRange(L, L) << Attr.getName();
+ << SourceRange(attr.getLoc())
+ << attr.getName() << isa<ObjCMethodDecl>(d) << cf;
return;
}
- switch (Attr.getKind()) {
+ switch (attr.getKind()) {
default:
assert(0 && "invalid ownership attribute");
return;
+ case AttributeList::AT_ns_returns_autoreleased:
+ d->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(attr.getLoc(),
+ S.Context));
+ return;
case AttributeList::AT_cf_returns_not_retained:
- d->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(Attr.getLoc(), S.Context));
+ d->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(attr.getLoc(),
+ S.Context));
return;
case AttributeList::AT_ns_returns_not_retained:
- d->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(Attr.getLoc(), S.Context));
+ d->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(attr.getLoc(),
+ S.Context));
return;
case AttributeList::AT_cf_returns_retained:
- d->addAttr(::new (S.Context) CFReturnsRetainedAttr(Attr.getLoc(), S.Context));
+ d->addAttr(::new (S.Context) CFReturnsRetainedAttr(attr.getLoc(),
+ S.Context));
return;
case AttributeList::AT_ns_returns_retained:
- d->addAttr(::new (S.Context) NSReturnsRetainedAttr(Attr.getLoc(), S.Context));
+ d->addAttr(::new (S.Context) NSReturnsRetainedAttr(attr.getLoc(),
+ S.Context));
return;
};
}
static bool isKnownDeclSpecAttr(const AttributeList &Attr) {
return Attr.getKind() == AttributeList::AT_dllimport ||
- Attr.getKind() == AttributeList::AT_dllexport;
+ Attr.getKind() == AttributeList::AT_dllexport ||
+ Attr.getKind() == AttributeList::AT_uuid;
+}
+
+//===----------------------------------------------------------------------===//
+// Microsoft specific attribute handlers.
+//===----------------------------------------------------------------------===//
+
+static void HandleUuidAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ if (S.LangOpts.Microsoft || S.LangOpts.Borland) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+ Expr *Arg = Attr.getArg(0);
+ StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
+ if (Str == 0 || Str->isWide()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
+ << "uuid" << 1;
+ return;
+ }
+
+ llvm::StringRef StrRef = Str->getString();
+
+ bool IsCurly = StrRef.size() > 1 && StrRef.front() == '{' &&
+ StrRef.back() == '}';
+
+ // Validate GUID length.
+ if (IsCurly && StrRef.size() != 38) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_uuid_malformed_guid);
+ return;
+ }
+ if (!IsCurly && StrRef.size() != 36) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_uuid_malformed_guid);
+ return;
+ }
+
+ // GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or
+ // "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
+ llvm::StringRef::iterator I = StrRef.begin();
+ if (IsCurly) // Skip the optional '{'
+ ++I;
+
+ for (int i = 0; i < 36; ++i) {
+ if (i == 8 || i == 13 || i == 18 || i == 23) {
+ if (*I != '-') {
+ S.Diag(Attr.getLoc(), diag::err_attribute_uuid_malformed_guid);
+ return;
+ }
+ } else if (!isxdigit(*I)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_uuid_malformed_guid);
+ return;
+ }
+ I++;
+ }
+
+ d->addAttr(::new (S.Context) UuidAttr(Attr.getLoc(), S.Context,
+ Str->getString()));
+ } else
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "uuid";
}
//===----------------------------------------------------------------------===//
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
-/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
-/// the attribute applies to decls. If the attribute is a type attribute, just
-/// silently ignore it if a GNU attribute. FIXME: Applying a C++0x attribute to
-/// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4).
-static void ProcessDeclAttribute(Scope *scope, Decl *D,
- const AttributeList &Attr, Sema &S) {
- if (Attr.isInvalid())
- return;
+static void ProcessNonInheritableDeclAttr(Scope *scope, Decl *D,
+ const AttributeList &Attr, Sema &S) {
+ switch (Attr.getKind()) {
+ case AttributeList::AT_device: HandleDeviceAttr (D, Attr, S); break;
+ case AttributeList::AT_host: HandleHostAttr (D, Attr, S); break;
+ case AttributeList::AT_overloadable:HandleOverloadableAttr(D, Attr, S); break;
+ default:
+ break;
+ }
+}
- if (Attr.isDeclspecAttribute() && !isKnownDeclSpecAttr(Attr))
- // FIXME: Try to deal with other __declspec attributes!
- return;
+static void ProcessInheritableDeclAttr(Scope *scope, Decl *D,
+ const AttributeList &Attr, Sema &S) {
switch (Attr.getKind()) {
case AttributeList::AT_IBAction: HandleIBAction(D, Attr, S); break;
case AttributeList::AT_IBOutlet: HandleIBOutlet(D, Attr, S); break;
@@ -2211,9 +2672,17 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_address_space:
case AttributeList::AT_objc_gc:
case AttributeList::AT_vector_size:
+ case AttributeList::AT_neon_vector_type:
+ case AttributeList::AT_neon_polyvector_type:
// Ignore these, these are type attributes, handled by
// ProcessTypeAttributes.
break;
+ case AttributeList::AT_device:
+ case AttributeList::AT_host:
+ case AttributeList::AT_overloadable:
+ // Ignore, this is a non-inheritable attribute, handled
+ // by ProcessNonInheritableDeclAttr.
+ break;
case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break;
case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break;
case AttributeList::AT_always_inline:
@@ -2221,33 +2690,45 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_analyzer_noreturn:
HandleAnalyzerNoReturnAttr (D, Attr, S); break;
case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break;
- case AttributeList::AT_base_check: HandleBaseCheckAttr (D, Attr, S); break;
case AttributeList::AT_carries_dependency:
HandleDependencyAttr (D, Attr, S); break;
+ case AttributeList::AT_common: HandleCommonAttr (D, Attr, S); break;
+ case AttributeList::AT_constant: HandleConstantAttr (D, Attr, S); break;
case AttributeList::AT_constructor: HandleConstructorAttr (D, Attr, S); break;
case AttributeList::AT_deprecated: HandleDeprecatedAttr (D, Attr, S); break;
case AttributeList::AT_destructor: HandleDestructorAttr (D, Attr, S); break;
case AttributeList::AT_ext_vector_type:
HandleExtVectorTypeAttr(scope, D, Attr, S);
break;
- case AttributeList::AT_final: HandleFinalAttr (D, Attr, S); break;
case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break;
case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break;
+ case AttributeList::AT_global: HandleGlobalAttr (D, Attr, S); break;
case AttributeList::AT_gnu_inline: HandleGNUInlineAttr (D, Attr, S); break;
- case AttributeList::AT_hiding: HandleHidingAttr (D, Attr, S); break;
+ case AttributeList::AT_launch_bounds:
+ HandleLaunchBoundsAttr(D, Attr, S);
+ break;
case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break;
case AttributeList::AT_malloc: HandleMallocAttr (D, Attr, S); break;
+ case AttributeList::AT_may_alias: HandleMayAliasAttr (D, Attr, S); break;
+ case AttributeList::AT_nocommon: HandleNoCommonAttr (D, Attr, S); break;
case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break;
case AttributeList::AT_ownership_returns:
case AttributeList::AT_ownership_takes:
case AttributeList::AT_ownership_holds:
HandleOwnershipAttr (D, Attr, S); break;
+ case AttributeList::AT_naked: HandleNakedAttr (D, Attr, S); break;
case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break;
case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break;
- case AttributeList::AT_override: HandleOverrideAttr (D, Attr, S); break;
+ case AttributeList::AT_shared: HandleSharedAttr (D, Attr, S); break;
case AttributeList::AT_vecreturn: HandleVecReturnAttr (D, Attr, S); break;
// Checker-specific.
+ case AttributeList::AT_cf_consumed:
+ case AttributeList::AT_ns_consumed: HandleNSConsumedAttr (D, Attr, S); break;
+ case AttributeList::AT_ns_consumes_self:
+ HandleNSConsumesSelfAttr(D, Attr, S); break;
+
+ case AttributeList::AT_ns_returns_autoreleased:
case AttributeList::AT_ns_returns_not_retained:
case AttributeList::AT_cf_returns_not_retained:
case AttributeList::AT_ns_returns_retained:
@@ -2277,7 +2758,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_objc_exception:
HandleObjCExceptionAttr(D, Attr, S);
break;
- case AttributeList::AT_overloadable:HandleOverloadableAttr(D, Attr, S); break;
case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break;
case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break;
case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break;
@@ -2300,6 +2780,12 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_pascal:
HandleCallConvAttr(D, Attr, S);
break;
+ case AttributeList::AT_opencl_kernel_function:
+ HandleOpenCLKernelAttr(D, Attr, S);
+ break;
+ case AttributeList::AT_uuid:
+ HandleUuidAttr(D, Attr, S);
+ break;
default:
// Ask target about the attribute.
const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema();
@@ -2310,17 +2796,40 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
}
}
+/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
+/// the attribute applies to decls. If the attribute is a type attribute, just
+/// silently ignore it if a GNU attribute. FIXME: Applying a C++0x attribute to
+/// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4).
+static void ProcessDeclAttribute(Scope *scope, Decl *D,
+ const AttributeList &Attr, Sema &S,
+ bool NonInheritable, bool Inheritable) {
+ if (Attr.isInvalid())
+ return;
+
+ if (Attr.isDeclspecAttribute() && !isKnownDeclSpecAttr(Attr))
+ // FIXME: Try to deal with other __declspec attributes!
+ return;
+
+ if (NonInheritable)
+ ProcessNonInheritableDeclAttr(scope, D, Attr, S);
+
+ if (Inheritable)
+ ProcessInheritableDeclAttr(scope, D, Attr, S);
+}
+
/// ProcessDeclAttributeList - Apply all the decl attributes in the specified
/// attribute list to the specified decl, ignoring any type attributes.
-void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList) {
+void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
+ const AttributeList *AttrList,
+ bool NonInheritable, bool Inheritable) {
for (const AttributeList* l = AttrList; l; l = l->getNext()) {
- ProcessDeclAttribute(S, D, *l, *this);
+ ProcessDeclAttribute(S, D, *l, *this, NonInheritable, Inheritable);
}
// GCC accepts
// static int a9 __attribute__((weakref));
// but that looks really pointless. We reject it.
- if (D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) {
+ if (Inheritable && D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) {
Diag(AttrList->getLoc(), diag::err_attribute_weakref_without_alias) <<
dyn_cast<NamedDecl>(D)->getNameAsString();
return;
@@ -2380,22 +2889,27 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
/// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in
/// it, apply them to D. This is a bit tricky because PD can have attributes
/// specified in many different places, and we need to find and apply them all.
-void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
- // Handle #pragma weak
- if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
- if (ND->hasLinkage()) {
- WeakInfo W = WeakUndeclaredIdentifiers.lookup(ND->getIdentifier());
- if (W != WeakInfo()) {
- // Identifier referenced by #pragma weak before it was declared
- DeclApplyPragmaWeak(S, ND, W);
- WeakUndeclaredIdentifiers[ND->getIdentifier()] = W;
+void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD,
+ bool NonInheritable, bool Inheritable) {
+ // It's valid to "forward-declare" #pragma weak, in which case we
+ // have to do this.
+ if (Inheritable && !WeakUndeclaredIdentifiers.empty()) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ if (IdentifierInfo *Id = ND->getIdentifier()) {
+ llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I
+ = WeakUndeclaredIdentifiers.find(Id);
+ if (I != WeakUndeclaredIdentifiers.end() && ND->hasLinkage()) {
+ WeakInfo W = I->second;
+ DeclApplyPragmaWeak(S, ND, W);
+ WeakUndeclaredIdentifiers[Id] = W;
+ }
}
}
}
// Apply decl attributes from the DeclSpec if present.
- if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes())
- ProcessDeclAttributeList(S, D, Attrs);
+ if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes().getList())
+ ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable);
// Walk the declarator structure, applying decl attributes that were in a type
// position to the decl itself. This handles cases like:
@@ -2403,66 +2917,84 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
// when X is a decl attribute.
for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i)
if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs())
- ProcessDeclAttributeList(S, D, Attrs);
+ ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable);
// Finally, apply any attributes on the decl itself.
if (const AttributeList *Attrs = PD.getAttributes())
- ProcessDeclAttributeList(S, D, Attrs);
+ ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable);
}
-/// PushParsingDeclaration - Enter a new "scope" of deprecation
-/// warnings.
-///
-/// The state token we use is the start index of this scope
-/// on the warning stack.
-Sema::ParsingDeclStackState Sema::PushParsingDeclaration() {
- ParsingDeclDepth++;
- return (ParsingDeclStackState) DelayedDiagnostics.size();
+// This duplicates a vector push_back but hides the need to know the
+// size of the type.
+void Sema::DelayedDiagnostics::add(const DelayedDiagnostic &diag) {
+ assert(StackSize <= StackCapacity);
+
+ // Grow the stack if necessary.
+ if (StackSize == StackCapacity) {
+ unsigned newCapacity = 2 * StackCapacity + 2;
+ char *newBuffer = new char[newCapacity * sizeof(DelayedDiagnostic)];
+ const char *oldBuffer = (const char*) Stack;
+
+ if (StackCapacity)
+ memcpy(newBuffer, oldBuffer, StackCapacity * sizeof(DelayedDiagnostic));
+
+ delete[] oldBuffer;
+ Stack = reinterpret_cast<sema::DelayedDiagnostic*>(newBuffer);
+ StackCapacity = newCapacity;
+ }
+
+ assert(StackSize < StackCapacity);
+ new (&Stack[StackSize++]) DelayedDiagnostic(diag);
}
-void Sema::PopParsingDeclaration(ParsingDeclStackState S, Decl *D) {
- assert(ParsingDeclDepth > 0 && "empty ParsingDeclaration stack");
- ParsingDeclDepth--;
+void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state,
+ Decl *decl) {
+ DelayedDiagnostics &DD = S.DelayedDiagnostics;
- if (DelayedDiagnostics.empty())
- return;
+ // Check the invariants.
+ assert(DD.StackSize >= state.SavedStackSize);
+ assert(state.SavedStackSize >= DD.ActiveStackBase);
+ assert(DD.ParsingDepth > 0);
- unsigned SavedIndex = (unsigned) S;
- assert(SavedIndex <= DelayedDiagnostics.size() &&
- "saved index is out of bounds");
+ // Drop the parsing depth.
+ DD.ParsingDepth--;
- unsigned E = DelayedDiagnostics.size();
+ // If there are no active diagnostics, we're done.
+ if (DD.StackSize == DD.ActiveStackBase)
+ return;
// We only want to actually emit delayed diagnostics when we
// successfully parsed a decl.
- if (D) {
- // We really do want to start with 0 here. We get one push for a
+ if (decl) {
+ // We emit all the active diagnostics, not just those starting
+ // from the saved state. The idea is this: we get one push for a
// decl spec and another for each declarator; in a decl group like:
// deprecated_typedef foo, *bar, baz();
// only the declarator pops will be passed decls. This is correct;
// we really do need to consider delayed diagnostics from the decl spec
// for each of the different declarations.
- for (unsigned I = 0; I != E; ++I) {
- if (DelayedDiagnostics[I].Triggered)
+ for (unsigned i = DD.ActiveStackBase, e = DD.StackSize; i != e; ++i) {
+ DelayedDiagnostic &diag = DD.Stack[i];
+ if (diag.Triggered)
continue;
- switch (DelayedDiagnostics[I].Kind) {
+ switch (diag.Kind) {
case DelayedDiagnostic::Deprecation:
- HandleDelayedDeprecationCheck(DelayedDiagnostics[I], D);
+ S.HandleDelayedDeprecationCheck(diag, decl);
break;
case DelayedDiagnostic::Access:
- HandleDelayedAccessCheck(DelayedDiagnostics[I], D);
+ S.HandleDelayedAccessCheck(diag, decl);
break;
}
}
}
// Destroy all the delayed diagnostics we're about to pop off.
- for (unsigned I = SavedIndex; I != E; ++I)
- DelayedDiagnostics[I].destroy();
+ for (unsigned i = state.SavedStackSize, e = DD.StackSize; i != e; ++i)
+ DD.Stack[i].destroy();
- DelayedDiagnostics.set_size(SavedIndex);
+ DD.StackSize = state.SavedStackSize;
}
static bool isDeclDeprecated(Decl *D) {
@@ -2479,20 +3011,34 @@ void Sema::HandleDelayedDeprecationCheck(DelayedDiagnostic &DD,
return;
DD.Triggered = true;
- Diag(DD.Loc, diag::warn_deprecated)
- << DD.DeprecationData.Decl->getDeclName();
+ if (!DD.getDeprecationMessage().empty())
+ Diag(DD.Loc, diag::warn_deprecated_message)
+ << DD.getDeprecationDecl()->getDeclName()
+ << DD.getDeprecationMessage();
+ else
+ Diag(DD.Loc, diag::warn_deprecated)
+ << DD.getDeprecationDecl()->getDeclName();
}
-void Sema::EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc) {
+void Sema::EmitDeprecationWarning(NamedDecl *D, llvm::StringRef Message,
+ SourceLocation Loc,
+ bool UnknownObjCClass) {
// Delay if we're currently parsing a declaration.
- if (ParsingDeclDepth) {
- DelayedDiagnostics.push_back(DelayedDiagnostic::makeDeprecation(Loc, D));
+ if (DelayedDiagnostics.shouldDelayDiagnostics()) {
+ DelayedDiagnostics.add(DelayedDiagnostic::makeDeprecation(Loc, D, Message));
return;
}
// Otherwise, don't warn if our current context is deprecated.
if (isDeclDeprecated(cast<Decl>(CurContext)))
return;
-
- Diag(Loc, diag::warn_deprecated) << D->getDeclName();
+ if (!Message.empty())
+ Diag(Loc, diag::warn_deprecated_message) << D->getDeclName()
+ << Message;
+ else {
+ if (!UnknownObjCClass)
+ Diag(Loc, diag::warn_deprecated) << D->getDeclName();
+ else
+ Diag(Loc, diag::warn_deprecated_fwdclass_message) << D->getDeclName();
+ }
}
OpenPOWER on IntegriCloud