aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafael Espindola <rafael.espindola@gmail.com>2010-02-23 22:00:30 +0000
committerRafael Espindola <rafael.espindola@gmail.com>2010-02-23 22:00:30 +0000
commit11e8ce7380856abee188b237c2600272df2ed09d (patch)
tree189aaf5995f111e141000cdc9ebb8cea4de1ae63
parent2a7eb28397148079cbc8e54e8a3871ef01c4f4bc (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.h2
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td6
-rw-r--r--include/clang/Parse/AttributeList.h1
-rw-r--r--lib/AST/AttrImpl.cpp3
-rw-r--r--lib/CodeGen/CodeGenModule.cpp1
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp1
-rw-r--r--lib/Frontend/PCHWriter.cpp2
-rw-r--r--lib/Parse/AttributeList.cpp1
-rw-r--r--lib/Sema/SemaDeclAttr.cpp103
-rw-r--r--test/CodeGen/attributes.c6
-rw-r--r--test/SemaCXX/attr-weakref.cpp31
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}}