diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp | 1150 |
1 files changed, 848 insertions, 302 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp index 25af73a..cbc940f 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp +++ b/contrib/llvm/tools/clang/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(); + } } |