From b1c0e204046b72828e513bad369ab03252b2c42e Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Tue, 22 Oct 2013 21:39:03 +0000 Subject: [PATCH] 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@193200 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Attr.td | 2 +- include/clang/Basic/DiagnosticSemaKinds.td | 4 ++ include/clang/Sema/Sema.h | 4 +- lib/AST/Decl.cpp | 6 ++- lib/Sema/SemaDecl.cpp | 61 +++++++++++++++++++--- test/CodeGen/pragma-weak.c | 16 ------ test/Sema/alias-redefinition.c | 44 ++++++++++++++++ test/Sema/pragma-weak.c | 11 ++++ 8 files changed, 122 insertions(+), 26 deletions(-) create mode 100644 test/Sema/alias-redefinition.c create mode 100644 test/Sema/pragma-weak.c diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 381eaeb53d..d8ba91dcfe 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 8d8602d41c..f10cae41cb 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3500,6 +3500,10 @@ def warn_missing_variable_declarations : Warning< "no previous extern declaration for non-static variable %0">, InGroup>, 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 b1906ab4c6..0c68e5c37a 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 89eeb5e8a1..e18afb02c9 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()) + 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()) { Definition = I->IsDeleted ? I->getCanonicalDecl() : *I; return true; } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 325366bef7..d19d2c42a9 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(D)) return TD->getDefinition(); - if (const VarDecl *VD = dyn_cast(D)) - return VD->getDefinition(); + if (const VarDecl *VD = dyn_cast(D)) { + const VarDecl *Def = VD->getDefinition(); + if (Def) + return Def; + return VD->getActingDefinition(); + } if (const FunctionDecl *FD = dyn_cast(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(NewAttribute)) { + if (FunctionDecl *FD = dyn_cast(New)) + S.CheckForFunctionRedefinition(FD, cast(Def)); + else { + VarDecl *VD = cast(New); + unsigned Diag = cast(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(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()) { + 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() && diff --git a/test/CodeGen/pragma-weak.c b/test/CodeGen/pragma-weak.c index 40eb525e18..559be831a5 100644 --- a/test/CodeGen/pragma-weak.c +++ b/test/CodeGen/pragma-weak.c @@ -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]+]] diff --git a/test/Sema/alias-redefinition.c b/test/Sema/alias-redefinition.c new file mode 100644 index 0000000000..6c6ebf8025 --- /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}} diff --git a/test/Sema/pragma-weak.c b/test/Sema/pragma-weak.c new file mode 100644 index 0000000000..c14125eac9 --- /dev/null +++ b/test/Sema/pragma-weak.c @@ -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) {} -- 2.40.0