#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/OpenMPKinds.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
return DG;
}
+static void setPrototype(Sema &S, FunctionDecl *FD, FunctionDecl *FDWithProto,
+ QualType NewType) {
+ assert(NewType->isFunctionProtoType() &&
+ "Expected function type with prototype.");
+ assert(FD->getType()->isFunctionNoProtoType() &&
+ "Expected function with type with no prototype.");
+ assert(FDWithProto->getType()->isFunctionProtoType() &&
+ "Expected function with prototype.");
+ // Synthesize parameters with the same types.
+ FD->setType(NewType);
+ SmallVector<ParmVarDecl *, 16> Params;
+ for (const ParmVarDecl *P : FDWithProto->parameters()) {
+ auto *Param = ParmVarDecl::Create(S.getASTContext(), FD, SourceLocation(),
+ SourceLocation(), nullptr, P->getType(),
+ /*TInfo=*/nullptr, SC_None, nullptr);
+ Param->setScopeInfo(0, Params.size());
+ Param->setImplicit();
+ Params.push_back(Param);
+ }
+
+ FD->setParams(Params);
+}
+
Optional<std::pair<FunctionDecl *, Expr *>>
Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
Expr *VariantRef, SourceRange SR) {
if (ICS.isFailure()) {
Diag(VariantRef->getExprLoc(),
diag::err_omp_declare_variant_incompat_types)
- << VariantRef->getType() << FnPtrType << VariantRef->getSourceRange();
+ << VariantRef->getType()
+ << ((Method && !Method->isStatic()) ? FnPtrType : FD->getType())
+ << VariantRef->getSourceRange();
return None;
}
VariantRefCast = PerformImplicitConversion(
return None;
}
+ // Check if function types are compatible in C.
+ if (!LangOpts.CPlusPlus) {
+ QualType NewType =
+ Context.mergeFunctionTypes(FD->getType(), NewFD->getType());
+ if (NewType.isNull()) {
+ Diag(VariantRef->getExprLoc(),
+ diag::err_omp_declare_variant_incompat_types)
+ << NewFD->getType() << FD->getType() << VariantRef->getSourceRange();
+ return None;
+ }
+ if (NewType->isFunctionProtoType()) {
+ if (FD->getType()->isFunctionNoProtoType())
+ setPrototype(*this, FD, NewFD, NewType);
+ else if (NewFD->getType()->isFunctionNoProtoType())
+ setPrototype(*this, NewFD, FD, NewType);
+ }
+ }
+
// Check if variant function is not marked with declare variant directive.
if (NewFD->hasAttrs() && NewFD->hasAttr<OMPDeclareVariantAttr>()) {
Diag(VariantRef->getExprLoc(),
// Check general compatibility.
if (areMultiversionVariantFunctionsCompatible(
- FD, NewFD, PDiag(diag::err_omp_declare_variant_noproto),
- PartialDiagnosticAt(
- SR.getBegin(),
- PDiag(diag::note_omp_declare_variant_specified_here) << SR),
+ FD, NewFD, PartialDiagnostic::NullDiagnostic(),
+ PartialDiagnosticAt(SourceLocation(),
+ PartialDiagnostic::NullDiagnostic()),
PartialDiagnosticAt(
VariantRef->getExprLoc(),
PDiag(diag::err_omp_declare_variant_doesnt_support)),
int b, c;
int no_proto();
-
-// expected-error@+3 {{function with '#pragma omp declare variant' must have a prototype}}
-// expected-note@+1 {{'#pragma omp declare variant' for function specified here}}
#pragma omp declare variant(no_proto) match(xxx={})
int no_proto_too();
+int proto1(int);
+// expected-note@+2 {{previous declaration is here}}
+#pragma omp declare variant(proto1) match(xxx={})
+int diff_proto();
+// expected-error@+1 {{conflicting types for 'diff_proto'}}
+int diff_proto(double);
+
+#pragma omp declare variant(no_proto) match(xxx={})
+int diff_proto1(double);
+
int after_use_variant(void);
int after_use();
int bar() {
int diff_cc_variant(void);
-// expected-error@+1 {{function with '#pragma omp declare variant' has a different calling convention}}
+// expected-error@+1 {{variant in '#pragma omp declare variant' with type 'int (void)' is incompatible with type 'int (void) __attribute__((vectorcall))'}}
#pragma omp declare variant(diff_cc_variant) match(xxx={})
__vectorcall int diff_cc(void);
int diff_ret_variant(void);
-// expected-error@+1 {{function with '#pragma omp declare variant' has a different return type}}
+// expected-error@+1 {{variant in '#pragma omp declare variant' with type 'int (void)' is incompatible with type 'void (void)'}}
#pragma omp declare variant(diff_ret_variant) match(xxx={})
void diff_ret(void);
b = 0;
}
-// expected-error@+1 {{variant in '#pragma omp declare variant' with type '<overloaded function type>' is incompatible with type 'void (*)(int *, int *, int *, int *)'}}
+// expected-error@+1 {{variant in '#pragma omp declare variant' with type '<overloaded function type>' is incompatible with type 'void (int *, int *, int *, int *)'}}
#pragma omp declare variant(barbar <int>) match(xxx = {})
template <>
void h(int *hp, int *hp2, int *hq, int *lin);
int fn1();
int fn1(int);
-// expected-error@+1 {{variant in '#pragma omp declare variant' with type '<overloaded function type>' is incompatible with type 'int (*)(float)'}}
+// expected-error@+1 {{variant in '#pragma omp declare variant' with type '<overloaded function type>' is incompatible with type 'int (float)'}}
#pragma omp declare variant(fn1) match(xxx = {})
int overload1(float);
auto fn_deduced3();
auto fn_deduced_variant2() { return 0; }
-// expected-error@+1 {{variant in '#pragma omp declare variant' with type 'int ()' is incompatible with type 'float (*)()'}}
+// expected-error@+1 {{variant in '#pragma omp declare variant' with type 'int ()' is incompatible with type 'float ()'}}
#pragma omp declare variant(fn_deduced_variant2) match(xxx = {})
float fn_deduced2();
void bar(int);
#pragma omp declare variant(SpecialFuncs::baz) match(xxx = {})
#pragma omp declare variant(SpecialFuncs::bar) match(xxx = {})
+// expected-error@+1 {{variant in '#pragma omp declare variant' with type 'int (*)()' is incompatible with type 'void (SpecialFuncs::*)()'}}
+#pragma omp declare variant(fn_sc_variant1) match(xxx = {})
void foo1();
SpecialFuncs& foo(const SpecialFuncs&);
SpecialFuncs& bar(SpecialFuncs&&);