Treat aliases as definitions.

This fixes pr17639.

Before this patch clang would consider

void foo(void) __attribute((alias("__foo")));

a declaration. It now correctly handles it as a definition.

Initial patch by Alp Toker. I added support for variables.

llvm-svn: 193200
This commit is contained in:
Rafael Espindola 2013-10-22 21:39:03 +00:00
parent f34568b0af
commit d53ffa0a70
8 changed files with 122 additions and 26 deletions

View File

@ -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">];
}

View File

@ -3500,6 +3500,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 "

View File

@ -1539,7 +1539,9 @@ public:
void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
SourceLocation LocAfterDecls);
void CheckForFunctionRedefinition(FunctionDecl *FD);
void CheckForFunctionRedefinition(FunctionDecl *FD,
const FunctionDecl *EffectiveDefinition =
0);
Decl *ActOnStartOfFunctionDef(Scope *S, Declarator &D);
Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D);
void ActOnStartOfObjCMethodDef(Scope *S, Decl *D);

View File

@ -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;
}

View File

@ -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,17 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
return MissingPrototype;
}
void Sema::CheckForFunctionRedefinition(FunctionDecl *FD) {
void
Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
const FunctionDecl *EffectiveDefinition) {
// 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()))
const FunctionDecl *Definition = EffectiveDefinition;
if (!Definition)
if (!FD->isDefined(Definition))
return;
if (canRedefineFunction(Definition, getLangOpts()))
return;
if (getLangOpts().GNUMode && Definition->isInlineSpecified() &&

View File

@ -7,8 +7,6 @@
// CHECK-DAG: @both = alias void ()* @__both
// CHECK-DAG: @both2 = alias void ()* @__both2
// CHECK-DAG: @both3 = alias weak void ()* @__both3
// CHECK-DAG: @a3 = alias weak void ()* @__a3
// CHECK-DAG: @weakvar_alias = alias weak i32* @__weakvar_alias
// CHECK-DAG: @foo = alias weak void ()* @__foo
// CHECK-DAG: @foo2 = alias weak void ()* @__foo2
@ -125,12 +123,6 @@ void both2(void) __attribute((alias("__both2"))); // first, wins
void __both2(void) {}
// CHECK-LABEL: define void @__both2()
void __both3(void);
#pragma weak both3 = __both3 // first, wins
void both3(void) __attribute((alias("__both3")));
void __both3(void) {}
// CHECK-LABEL: define void @__both3()
///////////// ensure that #pragma weak does not alter existing __attributes()
void __a1(void) __attribute((noinline));
@ -138,14 +130,6 @@ void __a1(void) __attribute((noinline));
void __a1(void) {}
// CHECK: define void @__a1() [[NI:#[0-9]+]]
// attributes introduced BEFORE a combination of #pragma weak and alias()
// hold...
void __a3(void) __attribute((noinline));
#pragma weak a3 = __a3
void a3(void) __attribute((alias("__a3")));
void __a3(void) {}
// CHECK: define void @__a3() [[NI]]
#pragma weak xxx = __xxx
__attribute((pure,noinline,const)) void __xxx(void) { }
// CHECK: void @__xxx() [[RN:#[0-9]+]]

View File

@ -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}}

View File

@ -0,0 +1,11 @@
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -verify %s
void __both3(void);
#pragma weak both3 = __both3 // expected-note {{previous definition}}
void both3(void) __attribute((alias("__both3"))); // expected-error {{redefinition of 'both3'}}
void __both3(void) {}
void __a3(void) __attribute((noinline));
#pragma weak a3 = __a3 // expected-note {{previous definition}}
void a3(void) __attribute((alias("__a3"))); // expected-error {{redefinition of 'a3'}}
void __a3(void) {}