diff options
author | Rafael Espindola <rafael.espindola@gmail.com> | 2010-02-23 22:00:30 +0000 |
---|---|---|
committer | Rafael Espindola <rafael.espindola@gmail.com> | 2010-02-23 22:00:30 +0000 |
commit | 11e8ce7380856abee188b237c2600272df2ed09d (patch) | |
tree | 189aaf5995f111e141000cdc9ebb8cea4de1ae63 | |
parent | 2a7eb28397148079cbc8e54e8a3871ef01c4f4bc (diff) |
Add support for the weakref attribute. We still produce "alias weak" as llvm-gcc does, but are more strict on what uses of weakref we accept.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96992 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/Attr.h | 2 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 6 | ||||
-rw-r--r-- | include/clang/Parse/AttributeList.h | 1 | ||||
-rw-r--r-- | lib/AST/AttrImpl.cpp | 3 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.cpp | 1 | ||||
-rw-r--r-- | lib/Frontend/PCHReaderDecl.cpp | 1 | ||||
-rw-r--r-- | lib/Frontend/PCHWriter.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/AttributeList.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 103 | ||||
-rw-r--r-- | test/CodeGen/attributes.c | 6 | ||||
-rw-r--r-- | test/SemaCXX/attr-weakref.cpp | 31 |
11 files changed, 144 insertions, 13 deletions
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index dc44c266aa..1974493176 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -94,6 +94,7 @@ public: WarnUnusedResult, Weak, WeakImport, + WeakRef, FIRST_TARGET_ATTRIBUTE, DLLExport, @@ -357,6 +358,7 @@ DEF_SIMPLE_ATTR(Unused); DEF_SIMPLE_ATTR(Used); DEF_SIMPLE_ATTR(Weak); DEF_SIMPLE_ATTR(WeakImport); +DEF_SIMPLE_ATTR(WeakRef); DEF_SIMPLE_ATTR(NoThrow); DEF_SIMPLE_ATTR(Const); DEF_SIMPLE_ATTR(Pure); diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 919397b52c..07b0fdedcd 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -747,6 +747,12 @@ def err_attribute_weak_static : Error< "weak declaration of '%0' must be public">; def warn_attribute_weak_import_invalid_on_definition : Warning< "'weak_import' attribute cannot be specified on a definition">; +def err_attribute_weakref_not_static : Error< + "weakref declaration of '%0' must be static">; +def err_attribute_weakref_not_global_context : Error< + "weakref declaration of '%0' must be in a global context">; +def err_attribute_weakref_without_alias : Error< + "weakref declaration of '%0' must also have an alias attribute">; def warn_attribute_wrong_decl_type : Warning< "%0 attribute only applies to %select{function|union|" "variable and function|function or method|parameter|" diff --git a/include/clang/Parse/AttributeList.h b/include/clang/Parse/AttributeList.h index 030f88eca2..37acab9b01 100644 --- a/include/clang/Parse/AttributeList.h +++ b/include/clang/Parse/AttributeList.h @@ -109,6 +109,7 @@ public: AT_visibility, AT_warn_unused_result, AT_weak, + AT_weakref, AT_weak_import, AT_reqd_wg_size, IgnoredAttribute, diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp index fe7cb82b36..423aa065e5 100644 --- a/lib/AST/AttrImpl.cpp +++ b/lib/AST/AttrImpl.cpp @@ -107,6 +107,7 @@ DEF_SIMPLE_ATTR_CLONE(Used) DEF_SIMPLE_ATTR_CLONE(WarnUnusedResult) DEF_SIMPLE_ATTR_CLONE(Weak) DEF_SIMPLE_ATTR_CLONE(WeakImport) +DEF_SIMPLE_ATTR_CLONE(WeakRef) DEF_SIMPLE_ATTR_CLONE(X86ForceAlignArgPointer) Attr* PragmaPackAttr::clone(ASTContext &C) const { @@ -196,5 +197,3 @@ Attr *ReqdWorkGroupSizeAttr::clone(ASTContext &C) const { Attr *MSP430InterruptAttr::clone(ASTContext &C) const { return ::new (C) MSP430InterruptAttr(Number); } - - diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index f819382a93..5236619088 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1327,6 +1327,7 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) { GA->setLinkage(llvm::Function::DLLExportLinkage); } } else if (D->hasAttr<WeakAttr>() || + D->hasAttr<WeakRefAttr>() || D->hasAttr<WeakImportAttr>()) { GA->setLinkage(llvm::Function::WeakAnyLinkage); } diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 27349ecbfe..356bd0726e 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -586,6 +586,7 @@ Attr *PCHReader::ReadAttributes() { SIMPLE_ATTR(WarnUnusedResult); SIMPLE_ATTR(Weak); + SIMPLE_ATTR(WeakRef); SIMPLE_ATTR(WeakImport); } diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index f40facb9f4..93af754683 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -1916,6 +1916,7 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) { case Attr::WarnUnusedResult: case Attr::Weak: + case Attr::WeakRef: case Attr::WeakImport: break; } @@ -2335,4 +2336,3 @@ void PCHWriter::AddDeclarationName(DeclarationName Name, RecordData &Record) { break; } } - diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp index 43722ad0dc..b96dff573d 100644 --- a/lib/Parse/AttributeList.cpp +++ b/lib/Parse/AttributeList.cpp @@ -57,6 +57,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { // FIXME: Hand generating this is neither smart nor efficient. return llvm::StringSwitch<AttributeList::Kind>(AttrName) .Case("weak", AT_weak) + .Case("weakref", AT_weakref) .Case("pure", AT_pure) .Case("mode", AT_mode) .Case("used", AT_used) diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 8178a14751..8a8ad28def 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -329,6 +329,86 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) NonNullAttr(S.Context, start, size)); } +static bool isStaticVarOrStaticFunciton(Decl *D) { + if (VarDecl *VD = dyn_cast<VarDecl>(D)) + return VD->getStorageClass() == VarDecl::Static; + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + return FD->getStorageClass() == FunctionDecl::Static; + return false; +} + +static void HandleWeakRefAttr(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; + } + + // gcc rejects + // class c { + // static int a __attribute__((weakref ("v2"))); + // static int b() __attribute__((weakref ("f3"))); + // }; + // and ignores the attributes of + // void f(void) { + // static int a __attribute__((weakref ("v2"))); + // } + // we reject them + if (const DeclContext *Ctx = d->getDeclContext()) { + Ctx = Ctx->getLookupContext(); + if (!isa<TranslationUnitDecl>(Ctx) && !isa<NamespaceDecl>(Ctx) ) { + S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_global_context) << + dyn_cast<NamedDecl>(d)->getNameAsString(); + return; + } + } + + // The GCC manual says + // + // At present, a declaration to which `weakref' is attached can only + // be `static'. + // + // It also says + // + // Without a TARGET, + // given as an argument to `weakref' or to `alias', `weakref' is + // equivalent to `weak'. + // + // gcc 4.4.1 will accept + // int a7 __attribute__((weakref)); + // as + // int a7 __attribute__((weak)); + // 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(); + return; + } + + // GCC rejects + // static ((alias ("y"), weakref)). + // Should we? How to check that weakref is before or after alias? + + if (Attr.getNumArgs() == 1) { + Expr *Arg = static_cast<Expr*>(Attr.getArg(0)); + Arg = Arg->IgnoreParenCasts(); + StringLiteral *Str = dyn_cast<StringLiteral>(Arg); + + if (Str == 0 || Str->isWide()) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) + << "weakref" << 1; + return; + } + // GCC will accept anything as the argument of weakref. Should we + // check for an existing decl? + d->addAttr(::new (S.Context) AliasAttr(S.Context, Str->getString())); + } + + d->addAttr(::new (S.Context) WeakRefAttr()); +} + static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() != 1) { @@ -777,13 +857,7 @@ static void HandleWeakAttr(Decl *D, const AttributeList &Attr, Sema &S) { } /* weak only applies to non-static declarations */ - bool isStatic = false; - if (VarDecl *VD = dyn_cast<VarDecl>(D)) { - isStatic = VD->getStorageClass() == VarDecl::Static; - } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - isStatic = FD->getStorageClass() == FunctionDecl::Static; - } - if (isStatic) { + if (isStaticVarOrStaticFunciton(D)) { S.Diag(Attr.getLoc(), diag::err_attribute_weak_static) << dyn_cast<NamedDecl>(D)->getNameAsString(); return; @@ -1809,6 +1883,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_warn_unused_result: HandleWarnUnusedResult(D,Attr,S); break; case AttributeList::AT_weak: HandleWeakAttr (D, Attr, S); break; + case AttributeList::AT_weakref: HandleWeakRefAttr (D, Attr, S); break; case AttributeList::AT_weak_import: HandleWeakImportAttr (D, Attr, S); break; case AttributeList::AT_transparent_union: HandleTransparentUnionAttr(D, Attr, S); @@ -1847,9 +1922,17 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, /// 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) { - while (AttrList) { - ProcessDeclAttribute(S, D, *AttrList, *this); - AttrList = AttrList->getNext(); + for (const AttributeList* l = AttrList; l; l = l->getNext()) { + ProcessDeclAttribute(S, D, *l, *this); + } + + // GCC accepts + // static int a9 __attribute__((weakref)); + // but that looks really pointless. We reject it. + if (D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) { + Diag(AttrList->getLoc(), diag::err_attribute_weakref_without_alias) << + dyn_cast<NamedDecl>(D)->getNameAsString(); + return; } } diff --git a/test/CodeGen/attributes.c b/test/CodeGen/attributes.c index 770ce766df..4fdf1a5176 100644 --- a/test/CodeGen/attributes.c +++ b/test/CodeGen/attributes.c @@ -30,6 +30,12 @@ int t12 __attribute__((section("SECT"))); void __t8() {} void t9() __attribute__((weak, alias("__t8"))); +static void t22(void) __attribute__((weakref("t8"))); +// CHECK: @t22 = alias weak void ()* @t8 + +static void t23(void) __attribute__((weakref, alias("t8"))); +// CHECK: @t23 = alias weak void ()* @t8 + // CHECK: declare extern_weak i32 @t15() int __attribute__((weak_import)) t15(void); int t17() { diff --git a/test/SemaCXX/attr-weakref.cpp b/test/SemaCXX/attr-weakref.cpp new file mode 100644 index 0000000000..5773acc1ab --- /dev/null +++ b/test/SemaCXX/attr-weakref.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// GCC will accept anything as the argument of weakref. Should we +// check for an existing decl? +static int a1() __attribute__((weakref ("foo"))); +static int a2() __attribute__((weakref, alias ("foo"))); + +static int a3 __attribute__((weakref ("foo"))); +static int a4 __attribute__((weakref, alias ("foo"))); + +// gcc rejects, clang accepts +static int a5 __attribute__((alias ("foo"), weakref)); + +// this is pointless, but accepted by gcc. We reject it. +static int a6 __attribute__((weakref)); //expected-error {{weakref declaration of 'a6' must also have an alias attribute}} + +// gcc warns, clang rejects +void f(void) { + static int a __attribute__((weakref ("v2"))); // expected-error {{declaration of 'a' must be in a global context}} +} + +// both gcc and clang reject +class c { + static int a __attribute__((weakref ("v2"))); // expected-error {{declaration of 'a' must be in a global context}} + static int b() __attribute__((weakref ("f3"))); // expected-error {{declaration of 'b' must be in a global context}} +}; +int a7() __attribute__((weakref ("f1"))); // expected-error {{declaration of 'a7' must be static}} +int a8 __attribute__((weakref ("v1"))); // expected-error {{declaration of 'a8' must be static}} + +// gcc accepts this +int a9 __attribute__((weakref)); // expected-error {{declaration of 'a9' must be static}} |