Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -5703,32 +5703,39 @@ /// DeclClonePragmaWeak - clone existing decl (maybe definition), /// \#pragma weak needs a non-definition decl and source may not have one. -NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, - SourceLocation Loc) { +NamedDecl *Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, + SourceLocation Loc) { assert(isa(ND) || isa(ND)); NamedDecl *NewD = nullptr; + LookupResult Previous(*this, II, Loc, LookupOrdinaryName); + LookupParsedName(Previous, TUScope, nullptr, true); + + // If there is some previous declaration, prefer to use its type. + // Otherwise, use the type from the existing decl (weak default). + NamedDecl *PrevD = + Previous.isSingleResult() ? Previous.getRepresentativeDecl() : nullptr; if (FunctionDecl *FD = dyn_cast(ND)) { - FunctionDecl *NewFD; - // FIXME: Missing call to CheckFunctionDeclaration(). // FIXME: Mangling? // FIXME: Is the qualifier info correct? // FIXME: Is the DeclContext correct? - NewFD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(), - Loc, Loc, DeclarationName(II), - FD->getType(), FD->getTypeSourceInfo(), - SC_None, false/*isInlineSpecified*/, - FD->hasPrototype(), - false/*isConstexprSpecified*/); + auto PrevFD = dyn_cast_or_null(PrevD); + if (!PrevFD) + PrevFD = FD; + + auto NewFD = FunctionDecl::Create( + PrevFD->getASTContext(), PrevFD->getDeclContext(), Loc, Loc, + DeclarationName(II), PrevFD->getType(), PrevFD->getTypeSourceInfo(), + SC_None, PrevFD->isInlineSpecified(), PrevFD->hasPrototype(), + PrevFD->isConstexpr()); NewD = NewFD; - - if (FD->getQualifier()) - NewFD->setQualifierInfo(FD->getQualifierLoc()); + if (PrevFD->getQualifier()) + NewFD->setQualifierInfo(PrevFD->getQualifierLoc()); // Fake up parameter variables; they are declared as if this were // a typedef. - QualType FDTy = FD->getType(); + QualType FDTy = PrevFD->getType(); if (const FunctionProtoType *FT = FDTy->getAs()) { - SmallVector Params; + SmallVector Params; for (const auto &AI : FT->param_types()) { ParmVarDecl *Param = BuildParmVarDeclForTypedef(NewFD, Loc, AI); Param->setScopeInfo(0, Params.size()); @@ -5736,15 +5743,22 @@ } NewFD->setParams(Params); } + CheckFunctionDeclaration(TUScope, NewFD, Previous, + false /*IsExplicitSpecialization*/); } else if (VarDecl *VD = dyn_cast(ND)) { - NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(), - VD->getInnerLocStart(), VD->getLocation(), II, - VD->getType(), VD->getTypeSourceInfo(), - VD->getStorageClass()); - if (VD->getQualifier()) { - VarDecl *NewVD = cast(NewD); - NewVD->setQualifierInfo(VD->getQualifierLoc()); - } + auto PrevVD = dyn_cast_or_null(PrevD); + if (!PrevVD) + PrevVD = VD; + + auto NewVD = + VarDecl::Create(PrevVD->getASTContext(), PrevVD->getDeclContext(), Loc, + Loc, II, PrevVD->getType(), PrevVD->getTypeSourceInfo(), + PrevVD->getStorageClass()); + NewD = NewVD; + if (PrevVD->getQualifier()) + NewVD->setQualifierInfo(PrevVD->getQualifierLoc()); + + CheckVariableDeclaration(NewVD, Previous); } return NewD; } @@ -5755,6 +5769,12 @@ if (W.getUsed()) return; // only do this once W.setUsed(true); if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...)) + if (S != TUScope) { + // Use the same error message as emitted in CodeGen (when pragma appears + // after declaration), for symmetry. + Diag(W.getLocation(), diag::err_alias_to_undefined); + return; + } IdentifierInfo *NDId = ND->getIdentifier(); NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias(), W.getLocation()); NewD->addAttr(AliasAttr::CreateImplicit(Context, NDId->getName(), Index: test/CodeGen/pragma-weak.c =================================================================== --- test/CodeGen/pragma-weak.c +++ test/CodeGen/pragma-weak.c @@ -17,6 +17,12 @@ // CHECK-DAG: @mix2 = weak alias void (), void ()* @__mix2 // CHECK-DAG: @a1 = weak alias void (), void ()* @__a1 // CHECK-DAG: @xxx = weak alias void (), void ()* @__xxx +// CHECK-DAG: @weakfoo = weak alias void {{.*}} @localfoo +// CHECK-DAG: @f1 = weak alias {{.*}} @g1 +// CHECK-DAG: @f2 = weak alias {{.*}} @g2 +// CHECK-DAG: @zzzz = weak alias {{.*}} @global_z +// CHECK-DAG: @yyyy = weak alias {{.*}} @global_y +// CHECK-DAG: @wwww = weak alias {{.*}} @global_w @@ -173,6 +179,41 @@ // CHECK: declare extern_weak i32 @PR16705b() // CHECK: declare extern_weak i32 @PR16705c() +// In this test case, we have a declaration of weakfoo before #pragma weak. +// Test that 2 decls for the weakfoo are merged. +extern void weakfoo(); +void localfoo() { } +#pragma weak weakfoo=localfoo +extern void externmain() { return weakfoo(); } +// CHECK-LABEL: define void @externmain() +// CHECK: call{{.*}}@weakfoo + +int f1(char *); +int g1(char *); +#pragma weak f1 = g1 +int g1(char *p) {return *p;} + +struct s { int a; int b; }; +struct s_impl { char a[4]; double b; }; +int f2(struct s *, int); +int g2(struct s_impl *, int); +#pragma weak f2 = g2 +int g2(struct s_impl * p, int d) {return p->a[0] + d;} + +// Pragma weak alias for a variable, test that the variable decls are merged +int zzzz; +int global_z = 123; +#pragma weak zzzz=global_z +int global_y = 123; +#pragma weak yyyy=global_y +int yyyy; +int global_w = 123; +#pragma weak wwww=global_w +int get_zzzz() { return zzzz + yyyy + wwww; } +// CHECK-LABEL: define {{.*}}@get_zzzz +// CHECK: load {{.*}}@zzzz +// CHECK: load {{.*}}@yyyy +// CHECK: load {{.*}}@wwww ///////////// TODO: stuff that still doesn't work Index: test/CodeGenCXX/pragma-weak.cpp =================================================================== --- test/CodeGenCXX/pragma-weak.cpp +++ test/CodeGenCXX/pragma-weak.cpp @@ -6,6 +6,8 @@ // Different c++ ABIs may or may not mangle this, so we produce a strong // symbol. // CHECK: @zex = global i32 +// +// CHECK-DAG: @zzzz = weak alias {{.*}} @global_x #pragma weak foo struct S { void foo(); }; @@ -29,3 +31,11 @@ // GCC produces a weak symbol for this one, but it doesn't look like a good // idea to expose the mangling to the pragma unless we really have to. // CHECK-LABEL: define {{.*}}void @_Z3baxv( + +extern "C" int zzzz; +int global_x = 123; +#pragma weak zzzz=global_x +int get_zzzz() { return zzzz; } +// CHECK-LABEL: define {{.*}}@_Z8get_zzzzv +// CHECK: load {{.*}}@zzzz + Index: test/Sema/pragma-weak.c =================================================================== --- test/Sema/pragma-weak.c +++ test/Sema/pragma-weak.c @@ -9,3 +9,13 @@ #pragma weak a3 = __a3 // expected-note {{previous definition}} void a3(void) __attribute((alias("__a3"))); // expected-error {{redefinition of 'a3'}} void __a3(void) {} + +extern void weak2foo(int); +void local2foo(double d1, double d2) { } +#pragma weak weak2foo=local2foo // expected-note {{'weak2foo' declared here}} +#pragma weak weak3foo=local2foo // expected-note {{'weak3foo' declared here}} +extern void extern2main() { + return weak2foo() // expected-error {{too few arguments to function call, expected 1, have 0}} + + weak3foo(); // expected-error {{too few arguments to function call, expected 2, have 0}} +} + Index: test/SemaCXX/pragma-weak.cpp =================================================================== --- test/SemaCXX/pragma-weak.cpp +++ test/SemaCXX/pragma-weak.cpp @@ -1,11 +1,17 @@ -// RUN: %clang_cc1 %s +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -verify %s -#pragma weak foo +#pragma weak foo // expected-warning {{weak identifier 'foo' never declared}} static void foo(); extern "C" { void foo() { }; } -extern "C" int Test; -#pragma weak test = Test +// Do not allow extern "C" scope. +#pragma weak test1 = Test1 // expected-error {{alias must point to a defined variable or function}} +extern "C" int Test1; + +// The following would lead to the same error message, but during code gen. +extern "C" int Test2; +#pragma weak test2 = Test2 +