diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 423ccbd293d2c3..c91ef356f94471 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9696,10 +9696,6 @@ def warn_omp_declare_variant_after_used : Warning< def warn_omp_declare_variant_after_emitted : Warning< "'#pragma omp declare variant' cannot be applied to the function that was defined already;" " the original function might be used">, InGroup; -def err_omp_declare_variant_noproto : Error< - "function with '#pragma omp declare variant' must have a prototype">; -def note_omp_declare_variant_specified_here : Note< - "'#pragma omp declare variant' for function specified here">; def err_omp_declare_variant_doesnt_support : Error< "'#pragma omp declare variant' does not " "support %select{function templates|virtual functions|" diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index c2571245201375..ebc919b52a49a6 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9828,13 +9828,15 @@ bool Sema::areMultiversionVariantFunctionsCompatible( Linkage = 5, }; - if (OldFD && !OldFD->getType()->getAs()) { + if (NoProtoDiagID.getDiagID() != 0 && OldFD && + !OldFD->getType()->getAs()) { Diag(OldFD->getLocation(), NoProtoDiagID); Diag(NoteCausedDiagIDAt.first, NoteCausedDiagIDAt.second); return true; } - if (!NewFD->getType()->getAs()) + if (NoProtoDiagID.getDiagID() != 0 && + !NewFD->getType()->getAs()) return Diag(NewFD->getLocation(), NoProtoDiagID); if (!TemplatesSupported && diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index d876f04192b097..e02c1c591dff59 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -23,6 +23,7 @@ #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" @@ -5183,6 +5184,29 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( 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 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> Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, Expr *VariantRef, SourceRange SR) { @@ -5281,7 +5305,9 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, 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( @@ -5321,6 +5347,24 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, 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()) { Diag(VariantRef->getExprLoc(), @@ -5381,10 +5425,9 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, // 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)), diff --git a/clang/test/OpenMP/declare_variant_messages.c b/clang/test/OpenMP/declare_variant_messages.c index 79ba957a520b78..26507629ea370d 100644 --- a/clang/test/OpenMP/declare_variant_messages.c +++ b/clang/test/OpenMP/declare_variant_messages.c @@ -80,12 +80,19 @@ int main(); 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() { @@ -104,12 +111,12 @@ int defined1(void); 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); diff --git a/clang/test/OpenMP/declare_variant_messages.cpp b/clang/test/OpenMP/declare_variant_messages.cpp index 0a87fe5a69c0c2..ca1e4c33d17ee9 100644 --- a/clang/test/OpenMP/declare_variant_messages.cpp +++ b/clang/test/OpenMP/declare_variant_messages.cpp @@ -131,7 +131,7 @@ void h(C *hp, C *hp2, C *hq, C *lin) { b = 0; } -// expected-error@+1 {{variant in '#pragma omp declare variant' with type '' is incompatible with type 'void (*)(int *, int *, int *, int *)'}} +// expected-error@+1 {{variant in '#pragma omp declare variant' with type '' is incompatible with type 'void (int *, int *, int *, int *)'}} #pragma omp declare variant(barbar ) match(xxx = {}) template <> void h(int *hp, int *hp2, int *hq, int *lin); @@ -153,7 +153,7 @@ int overload(void); int fn1(); int fn1(int); -// expected-error@+1 {{variant in '#pragma omp declare variant' with type '' is incompatible with type 'int (*)(float)'}} +// expected-error@+1 {{variant in '#pragma omp declare variant' with type '' is incompatible with type 'int (float)'}} #pragma omp declare variant(fn1) match(xxx = {}) int overload1(float); @@ -201,7 +201,7 @@ auto fn_deduced3() { return 0; } 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(); @@ -231,6 +231,8 @@ struct SpecialFuncs { 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&&);