diff --git a/ClangAstParser/clang-dumper-release.tag b/ClangAstParser/clang-dumper-release.tag index 73e74e98f..91967a831 100644 --- a/ClangAstParser/clang-dumper-release.tag +++ b/ClangAstParser/clang-dumper-release.tag @@ -1 +1 @@ -v18.1.8_2 +v18.1.8_4 diff --git a/ClangAstParser/src/pt/up/fe/specs/clang/ClangResources.java b/ClangAstParser/src/pt/up/fe/specs/clang/ClangResources.java index 041f66e56..daf9ae46b 100644 --- a/ClangAstParser/src/pt/up/fe/specs/clang/ClangResources.java +++ b/ClangAstParser/src/pt/up/fe/specs/clang/ClangResources.java @@ -363,9 +363,14 @@ private File findSystemClangResourceDir(Integer llvmMajor) { var expectedVersion = llvmMajor == null ? "the local clang-dumper build's version" : "LLVM " + llvmMajor; + var installHint = llvmMajor == null ? "clang++" : "clang++-" + llvmMajor; throw new RuntimeException("Could not find a system Clang resource directory for SYSTEM mode with built-in CUDA" + " on host '" + SupportedPlatform.getCurrentPlatform() + "' (expected " + expectedVersion - + "). Tried: " + commandNames); + + "). Tried: " + commandNames + + ". SYSTEM mode does not bundle Clang's CUDA wrapper headers, so a matching system Clang" + + " installation is required: install '" + installHint + "' (e.g. 'apt install " + installHint + + "' or 'brew install llvm'), or set the libc mode to 'builtin' to use the bundled includes" + + " instead of the system libc"); } private static List getSystemClangCommandNames(Integer llvmMajor) { diff --git a/ClangAstParser/src/pt/up/fe/specs/clang/CudaResources.java b/ClangAstParser/src/pt/up/fe/specs/clang/CudaResources.java index 28641b5ab..30ea7ecc0 100644 --- a/ClangAstParser/src/pt/up/fe/specs/clang/CudaResources.java +++ b/ClangAstParser/src/pt/up/fe/specs/clang/CudaResources.java @@ -57,7 +57,8 @@ * the bundled dumper. * *

CUDA resources are release-addressed. The published release directory is the complete CUDA installation; - * manifests and downloaded archives used to build it live in staging until that directory is published.

+ * manifests and downloaded archives used to build it live in staging until that directory is published. The + * redistribution manifest itself is cached at {@code /cuda/redistrib_.json} and reused across calls.

*/ final class CudaResources { @@ -117,7 +118,8 @@ static boolean isSupportedPlatform(Path cacheRoot) { } static boolean isSupportedPlatform(Path cacheRoot, FileResourceProvider manifestResource) { - return findSupportedPlatform(getCurrentManifest(cacheRoot, manifestResource)).isPresent(); + return findSupportedPlatform(readManifest(cacheRoot, ClangAstWebResource.getCudaReleaseTag(), + manifestResource)).isPresent(); } static CudaPlatform getCurrentPlatform() { @@ -125,7 +127,8 @@ static CudaPlatform getCurrentPlatform() { } static CudaPlatform getCurrentPlatform(Path cacheRoot) { - return requireSupportedPlatform(getCurrentManifest(cacheRoot)); + var releaseTag = ClangAstWebResource.getCudaReleaseTag(); + return requireSupportedPlatform(readManifest(cacheRoot, releaseTag, getManifestResource(releaseTag))); } static CudaPlatform getCurrentPlatform(NvidiaCudaManifest manifest) { @@ -183,30 +186,17 @@ private static RuntimeException unsupportedPlatform(NvidiaCudaManifest manifest, + ". Available manifest platform keys: " + getAvailablePlatformKeys(manifest)); } - private static NvidiaCudaManifest getCurrentManifest(Path cacheRoot) { - var releaseTag = ClangAstWebResource.getCudaReleaseTag(); - return getCurrentManifest(cacheRoot, releaseTag, getManifestResource(releaseTag)); - } - - private static NvidiaCudaManifest getCurrentManifest(Path cacheRoot, FileResourceProvider manifestResource) { - var releaseTag = ClangAstWebResource.getCudaReleaseTag(); - return getCurrentManifest(cacheRoot, releaseTag, manifestResource); - } - - private static NvidiaCudaManifest getCurrentManifest(Path cacheRoot, String releaseTag, - FileResourceProvider manifestResource) { - var cudaRoot = cacheRoot.resolve(CUDA_FOLDERNAME); - CacheFiles.deleteUnlockedStagingLocks(cacheRoot, cudaRoot); - var stagingDirectory = CacheFiles.createStagingDirectory(cacheRoot, cudaRoot, "." + releaseTag + ".tmp-"); - try { - return downloadManifest(cacheRoot, stagingDirectory.path(), releaseTag, manifestResource); - } finally { - try { - CacheFiles.delete(stagingDirectory.path()); - } finally { - stagingDirectory.close(); - } - } + // The manifest is installed to a stable cache path and reused across calls, so platform checks and the like do + // not re-download it on every invocation. Mirrors how ClangAstWebResource.getManifest caches the clang-dumper + // release manifest. + private static NvidiaCudaManifest readManifest(Path cacheRoot, String releaseTag, + FileResourceProvider manifestResource) { + var manifestFile = CacheFiles.installFile(cacheRoot, + cacheRoot.resolve(CUDA_FOLDERNAME).resolve(getManifestFilename(releaseTag)).toFile(), + manifestResource, null, "NVIDIA CUDA redistribution manifest"); + var manifest = parseManifest(SpecsIo.read(manifestFile)); + validateManifest(manifest, releaseTag); + return manifest; } private static boolean isCompatiblePlatform(String manifestPlatform, SupportedPlatform hostPlatform, diff --git a/ClangAstParser/src/pt/up/fe/specs/clang/parsers/data/ClavaDataParsers.java b/ClangAstParser/src/pt/up/fe/specs/clang/parsers/data/ClavaDataParsers.java index 531c6feea..2e3c7c9ff 100644 --- a/ClangAstParser/src/pt/up/fe/specs/clang/parsers/data/ClavaDataParsers.java +++ b/ClangAstParser/src/pt/up/fe/specs/clang/parsers/data/ClavaDataParsers.java @@ -60,6 +60,7 @@ import pt.up.fe.specs.clava.ast.expr.data.designator.Designator; import pt.up.fe.specs.clava.ast.expr.data.designator.FieldDesignator; import pt.up.fe.specs.clava.ast.expr.data.offsetof.OffsetOfArray; +import pt.up.fe.specs.clava.ast.expr.data.offsetof.OffsetOfBase; import pt.up.fe.specs.clava.ast.expr.data.offsetof.OffsetOfComponent; import pt.up.fe.specs.clava.ast.expr.data.offsetof.OffsetOfComponentKind; import pt.up.fe.specs.clava.ast.expr.data.offsetof.OffsetOfField; @@ -459,6 +460,9 @@ public static OffsetOfComponent offsetOfComponent(LineStream lines, ClangAstData case IDENTIFIER: component.set(OffsetOfIdentifier.FIELD_NAME, lines.nextLine()); break; + case BASE: + parserData.getClavaNodes().queueSetNode(component, OffsetOfBase.TYPE, lines.nextLine()); + break; default: throw new NotImplementedException(kind); } diff --git a/ClavaAst/src/pt/up/fe/specs/clava/ast/expr/OffsetOfExpr.java b/ClavaAst/src/pt/up/fe/specs/clava/ast/expr/OffsetOfExpr.java index bf5ab5083..2ef7f313f 100644 --- a/ClavaAst/src/pt/up/fe/specs/clava/ast/expr/OffsetOfExpr.java +++ b/ClavaAst/src/pt/up/fe/specs/clava/ast/expr/OffsetOfExpr.java @@ -50,18 +50,20 @@ private String getComponentsCode() { StringBuilder code = new StringBuilder(); - boolean isFirst = true; + boolean hasCode = false; for (OffsetOfComponent component : get(COMPONENTS)) { + String componentCode = component.getCode(); - if (component.isField() && !isFirst) { - code.append("."); + if (componentCode.isEmpty()) { + continue; } - code.append(component.getCode()); - - if (isFirst) { - isFirst = false; + if (component.isField() && hasCode) { + code.append("."); } + + code.append(componentCode); + hasCode = true; } return code.toString(); } diff --git a/ClavaAst/src/pt/up/fe/specs/clava/ast/expr/data/offsetof/OffsetOfBase.java b/ClavaAst/src/pt/up/fe/specs/clava/ast/expr/data/offsetof/OffsetOfBase.java new file mode 100644 index 000000000..b52ecf056 --- /dev/null +++ b/ClavaAst/src/pt/up/fe/specs/clava/ast/expr/data/offsetof/OffsetOfBase.java @@ -0,0 +1,39 @@ +/** + * Copyright 2026 SPeCS. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package pt.up.fe.specs.clava.ast.expr.data.offsetof; + +import org.suikasoft.jOptions.Datakey.DataKey; +import org.suikasoft.jOptions.Datakey.KeyFactory; + +import pt.up.fe.specs.clava.ast.type.Type; + +public class OffsetOfBase extends OffsetOfComponent { + + /// DATAKEYS BEGIN + + public final static DataKey TYPE = KeyFactory.object("type", Type.class); + + /// DATAKEYS END + + @Override + public String getCode() { + // Clang adds the base to the semantic path, but it is not part of the source designator. + return ""; + } + + @Override + public OffsetOfComponentKind getKind() { + return OffsetOfComponentKind.BASE; + } +} diff --git a/ClavaAst/src/pt/up/fe/specs/clava/ast/expr/data/offsetof/OffsetOfComponent.java b/ClavaAst/src/pt/up/fe/specs/clava/ast/expr/data/offsetof/OffsetOfComponent.java index bfe9330d5..bcd2765a8 100644 --- a/ClavaAst/src/pt/up/fe/specs/clava/ast/expr/data/offsetof/OffsetOfComponent.java +++ b/ClavaAst/src/pt/up/fe/specs/clava/ast/expr/data/offsetof/OffsetOfComponent.java @@ -41,6 +41,8 @@ public static OffsetOfComponent newInstance(OffsetOfComponentKind kind) { return new OffsetOfField(); case IDENTIFIER: return new OffsetOfIdentifier(); + case BASE: + return new OffsetOfBase(); default: throw new NotImplementedException(kind); }