// RUN: clang-cc -emit-llvm -o %t %s &&

#pragma weak weakvar
int weakvar;
// RUN: grep '@weakvar = weak global' %t | count 1 &&

#pragma weak weakdef
void weakdef(void) {}
// RUN: grep 'define weak void @weakdef()' %t | count 1 &&

#pragma weak param // expected-warning {{weak identifier 'param' never declared}}
#pragma weak correct_linkage
void f(int param) {
  int correct_linkage;
}
int correct_linkage;
// RUN: grep '@correct_linkage = weak global' %t | count 1 &&

#pragma weak weakvar_alias = __weakvar_alias
int __weakvar_alias;
// RUN: grep '@__weakvar_alias = common global' %t | count 1 &&
// RUN: grep '@weakvar_alias = alias weak i32\* @__weakvar_alias' %t | count 1 &&
//@weakvar_alias = alias weak i32* @__weakvar_alias

#pragma weak foo = __foo
void __foo(void) {}
// RUN: grep '@foo = alias weak void ()\* @__foo\>' %t | count 1 &&
// RUN: grep 'define void @__foo()' %t | count 1 &&


void __foo2(void) {}
#pragma weak foo2 = __foo2
// RUN: grep '@foo2 = alias weak void ()\* @__foo2\>' %t | count 1 &&
// RUN: grep 'define void @__foo2()' %t | count 1 &&


///// test errors

#pragma weak unused // expected-warning {{weak identifier 'unused' never declared}}
#pragma weak unused_alias = __unused_alias  // expected-warning {{weak identifier '__unused_alias' never declared}}

#pragma weak td // expected-warning {{weak identifier 'td' never declared}}
typedef int td;

#pragma weak td2 = __td2 // expected-warning {{weak identifier '__td2' never declared}}
typedef int __td2;


///// test weird cases

// test repeats

#pragma weak stutter = __stutter
#pragma weak stutter = __stutter
void __stutter(void) {}
// RUN: grep '@stutter = alias weak void ()\* @__stutter\>' %t | count 1 &&
// RUN: grep 'define void @__stutter()' %t | count 1 &&

void __stutter2(void) {}
#pragma weak stutter2 = __stutter2
#pragma weak stutter2 = __stutter2
// RUN: grep '@stutter2 = alias weak void ()\* @__stutter2\>' %t | count 1 &&
// RUN: grep 'define void @__stutter2()' %t | count 1 &&


// test decl/pragma weak order

void __declfirst(void);
#pragma weak declfirst = __declfirst
void __declfirst(void) {}
// RUN: grep '@declfirst = alias weak void ()\* @__declfirst\>' %t | count 1 &&
// RUN: grep 'define void @__declfirst()' %t | count 1 &&

void __declfirstattr(void) __attribute((noinline));
#pragma weak declfirstattr = __declfirstattr
void __declfirstattr(void) {}
// RUN: grep '@declfirstattr = alias weak void ()\* @__declfirstattr\>' %t | count 1 &&
// RUN: grep 'define void @__declfirstattr()' %t | count 1 &&

//// test that other attributes are preserved

//// ensure that pragma weak/__attribute((weak)) play nice

void mix(void);
#pragma weak mix
__attribute((weak)) void mix(void) { }
// RUN: grep 'define weak void @mix()' %t | count 1 &&

// ensure following __attributes are preserved and that only a single
// alias is generated
#pragma weak mix2 = __mix2
void __mix2(void) __attribute((noinline));
void __mix2(void) __attribute((noinline));
void __mix2(void) {}
// RUN: grep '@mix2 = alias weak void ()\* @__mix2\>' %t | count 1 &&
// RUN: grep 'define void @__mix2()' %t | count 1 &&

////////////// test #pragma weak/__attribute combinations

// if the SAME ALIAS is already declared then it overrides #pragma weak
// resulting in a non-weak alias in this case
void both(void) __attribute((alias("__both")));
#pragma weak both = __both
void __both(void) {}
// RUN: grep '@both = alias void ()\* @__both\>' %t | count 1 &&
// RUN: grep 'define void @__both()' %t | count 1 &&

// if the TARGET is previously declared then whichever aliasing method
// comes first applies and subsequent aliases are discarded.
// TODO: warn about this

void __both2(void);
void both2(void) __attribute((alias("__both2"))); // first, wins
#pragma weak both2 = __both2
void __both2(void) {}
// RUN: grep '@both2 = alias void ()\* @__both2\>' %t | count 1 &&
// RUN: grep 'define void @__both2()' %t | count 1 &&

void __both3(void);
#pragma weak both3 = __both3 // first, wins
void both3(void) __attribute((alias("__both3")));
void __both3(void) {}
// RUN: grep '@both3 = alias weak void ()\* @__both3\>' %t | count 1 &&
// RUN: grep 'define void @__both3()' %t | count 1 &&

///////////// ensure that #pragma weak does not alter existing __attributes()

void __a1(void) __attribute((noinline));
#pragma weak a1 = __a1
void __a1(void) {}
// RUN: grep '@a1 = alias weak void ()\* @__a1\>' %t | count 1 &&
// RUN: grep 'define void @__a1()' %t | count 1 &&

// 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) {}
// RUN: grep '@a3 = alias weak void ()\* @__a3\>' %t | count 1 &&
// RUN: grep 'define void @__a3()' %t | count 1 &&

#pragma weak xxx = __xxx
__attribute((pure,noinline,const,fastcall)) void __xxx(void) { }
// RUN: grep '@xxx = alias weak void ()\* @__xxx\>' %t | count 1 &&
// RUN: grep 'define .*fastcall.* void @__xxx()' %t | count 1 &&

/// TODO: stuff that still doesn't work

// due to the fact that disparate TopLevelDecls cannot affect each other
// (due to clang's Parser and ASTConsumer behavior, and quite reasonable)
// #pragma weak must appear before or within the same TopLevelDecl as it
// references.
void yyy(void){}
void zzz(void){}
#pragma weak yyy
// NOTE: weak doesn't apply, not before or in same TopLevelDec(!)
// RUN: grep 'define void @yyy()' %t | count 1
