>> So I don't think any of the Sema changes for PR17639 can help.
>>
>> Isn't it rather a question of getting CodeGen to emit the GlobalDecls in the
>> right order?
>
> It could probably be made to work, but it seems better to just ask
> sema if something is defined or not, in which case the output order is
> not important (as long as it is in the end of the TU).
>
> BTW, I took the liberty of fetching the bits for pr17639 from your
> patch. I will email an updated version in a sec.
No, you are right, we have to output this in a clever order. Codegen
cannot ask sema since it has only the mangled name.
Oh well, I have at least added support for variables in your patch. A
WIP version is attached. I will go back to trying to figure out a way
to output the aliases in the correct order.
Thanks,
Rafael
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 381eaeb..d8ba91d 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -173,7 +173,7 @@ def AddressSpace : TypeAttr {
let Args = [IntArgument<"AddressSpace">];
}
-def Alias : InheritableAttr {
+def Alias : Attr {
let Spellings = [GNU<"alias">, CXX11<"gnu", "alias">];
let Args = [StringArgument<"Aliasee">];
}
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 415c4b2..554f4f9 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3496,6 +3496,10 @@ def warn_missing_variable_declarations : Warning<
"no previous extern declaration for non-static variable %0">,
InGroup<DiagGroup<"missing-variable-declarations">>, DefaultIgnore;
def err_redefinition : Error<"redefinition of %0">;
+def err_alias_after_tentative :
+ Error<"alias definition of %0 after tentative definition">;
+def err_tentative_after_alias :
+ Error<"tentative definition of %0 after alias definition">;
def err_definition_of_implicitly_declared_member : Error<
"definition of implicitly declared %select{default constructor|copy "
"constructor|move constructor|copy assignment operator|move assignment "
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index b1906ab..31dce9b 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1539,7 +1539,8 @@ public:
void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
SourceLocation LocAfterDecls);
- void CheckForFunctionRedefinition(FunctionDecl *FD);
+ void CheckForFunctionRedefinition(FunctionDecl *FD,
+ const FunctionDecl *Definition = 0);
Decl *ActOnStartOfFunctionDef(Scope *S, Declarator &D);
Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D);
void ActOnStartOfObjCMethodDef(Scope *S, Decl *D);
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 89eeb5e..f4db4ec 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1762,6 +1762,9 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
if (hasInit())
return Definition;
+ if (hasAttr<AliasAttr>())
+ return Definition;
+
// A variable template specialization (other than a static data member
// template or an explicit specialization) is a declaration until we
// instantiate its initializer.
@@ -2223,7 +2226,8 @@ bool FunctionDecl::hasTrivialBody() const
bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
- if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed) {
+ if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed
+ || I->hasAttr<AliasAttr>()) {
Definition = I->IsDeleted ? I->getCanonicalDecl() : *I;
return true;
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 325366b..63d090f 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1996,11 +1996,15 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, InheritableAttr *Attr,
static const Decl *getDefinition(const Decl *D) {
if (const TagDecl *TD = dyn_cast<TagDecl>(D))
return TD->getDefinition();
- if (const VarDecl *VD = dyn_cast<VarDecl>(D))
- return VD->getDefinition();
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ const VarDecl *Def = VD->getDefinition();
+ if (Def)
+ return Def;
+ return VD->getActingDefinition();
+ }
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
const FunctionDecl* Def;
- if (FD->hasBody(Def))
+ if (FD->isDefined(Def))
return Def;
}
return NULL;
@@ -2029,6 +2033,32 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
AttrVec &NewAttributes = New->getAttrs();
for (unsigned I = 0, E = NewAttributes.size(); I != E;) {
const Attr *NewAttribute = NewAttributes[I];
+
+ if (isa<AliasAttr>(NewAttribute)) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(New))
+ S.CheckForFunctionRedefinition(FD, cast<FunctionDecl>(Def));
+ else {
+ VarDecl *VD = cast<VarDecl>(New);
+ unsigned Diag = cast<VarDecl>(Def)->isThisDeclarationADefinition() ==
+ VarDecl::TentativeDefinition
+ ? diag::err_alias_after_tentative
+ : diag::err_redefinition;
+ S.Diag(VD->getLocation(), Diag) << VD->getDeclName();
+ S.Diag(Def->getLocation(), diag::note_previous_definition);
+ VD->setInvalidDecl();
+ }
+ ++I;
+ continue;
+ }
+
+ if (const VarDecl *VD = dyn_cast<VarDecl>(Def)) {
+ // Tentative definitions are only interesting for the alias check above.
+ if (VD->isThisDeclarationADefinition() != VarDecl::Definition) {
+ ++I;
+ continue;
+ }
+ }
+
if (hasAttribute(Def, NewAttribute->getKind())) {
++I;
continue; // regular attr merging will take care of validating this.
@@ -8819,6 +8849,18 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
}
}
+ if (!VD->isInvalidDecl() &&
+ VD->isThisDeclarationADefinition() == VarDecl::TentativeDefinition) {
+ if (const VarDecl *Def = VD->getDefinition()) {
+ if (Def->hasAttr<AliasAttr>()) {
+ Diag(VD->getLocation(), diag::err_tentative_after_alias)
+ << VD->getDeclName();
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ VD->setInvalidDecl();
+ }
+ }
+ }
+
const DeclContext *DC = VD->getDeclContext();
// If there's a #pragma GCC visibility in scope, and this isn't a class
// member, set the visibility of this variable.
@@ -9323,12 +9365,15 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
return MissingPrototype;
}
-void Sema::CheckForFunctionRedefinition(FunctionDecl *FD) {
+void Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
+ const FunctionDecl *Definition) {
// Don't complain if we're in GNU89 mode and the previous definition
// was an extern inline function.
- const FunctionDecl *Definition;
- if (!FD->isDefined(Definition) ||
- canRedefineFunction(Definition, getLangOpts()))
+ if (!Definition)
+ if (!FD->isDefined(Definition))
+ return;
+
+ if (canRedefineFunction(Definition, getLangOpts()))
return;
if (getLangOpts().GNUMode && Definition->isInlineSpecified() &&
diff --git a/test/Sema/alias-redefinition.c b/test/Sema/alias-redefinition.c
new file mode 100644
index 0000000..4733cc9
--- /dev/null
+++ b/test/Sema/alias-redefinition.c
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -verify %s
+
+void f0() {}
+void fun0(void) __attribute((alias("f0")));
+
+void f1() {}
+void fun1() {} // expected-note {{previous definition}}
+void fun1(void) __attribute((alias("f1"))); // expected-error {{redefinition of 'fun1'}}
+
+void f2() {}
+void fun2(void) __attribute((alias("f2"))); // expected-note {{previous definition}}
+void fun2() {} // expected-error {{redefinition of 'fun2'}}
+
+void f3() {}
+void fun3(void) __attribute((alias("f3"))); // expected-note {{previous definition}}
+void fun3(void) __attribute((alias("f3"))); // expected-error {{redefinition of 'fun3'}}
+
+void f4() {}
+void fun4(void) __attribute((alias("f4")));
+void fun4(void);
+
+// FIXME: We should produce a special case error for this.
+void f5() {}
+void __attribute((alias("f5"))) fun5(void) {} // expected-error {{redefinition of 'fun5'}} // expected-note {{previous definition}}
+
+int v1;
+int var1 __attribute((alias("v1"))); // expected-note {{previous definition}}
+int var1 __attribute((alias("v1"))); // expected-error {{redefinition of 'var1'}}
+
+int v2;
+int var2 = 2; // expected-note {{previous definition}}
+int var2 __attribute((alias("v2"))); // expected-error {{redefinition of 'var2'}}
+
+int v3;
+int var3 __attribute((alias("v3"))); // expected-note {{previous definition}}
+int var3 = 2; // expected-error {{redefinition of 'var3'}}
+
+int v4;
+int var4; // expected-note {{previous definition}}
+int var4 __attribute((alias("v4"))); // expected-error {{alias definition of 'var4' after tentative definition}}
+
+int v5;
+int var5 __attribute((alias("v5"))); // expected-note {{previous definition}}
+int var5; // expected-error {{tentative definition of 'var5' after alias definition}}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits